From 753ec8d53156d1da266c68089469b38d6aac19e2 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 10:37:30 -0700 Subject: [PATCH 001/259] feat(build): use gestalt's parser for module.txt It has the deserializer to give us type-safe access to this structure. And it will come in handy when we want to inspect the dependencies more thoroughly. --- .idea/.gitignore | 3 + buildSrc/build.gradle.kts | 12 ++++ .../main/kotlin/terasology-module.gradle.kts | 58 +++++++------------ 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/.idea/.gitignore b/.idea/.gitignore index 04b96835fe2..7f3351be8bb 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -31,3 +31,6 @@ workspace.xml # Ignore Sonar linting, if set up locally /sonarlint/ + +# Discord preferences don't need sharing +/discord.xml diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 9515d14a8a9..d6c609a400d 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,16 +1,28 @@ // Copyright 2020 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +import java.net.URI + plugins { `kotlin-dsl` } repositories { jcenter() + + maven { + name = "Terasology Artifactory" + url = URI("http://artifactory.terasology.org/artifactory/virtual-repo-live") + @Suppress("UnstableApiUsage") + isAllowInsecureProtocol = true // 😱 + } } dependencies { // Needed for caching reflected data during builds implementation("org.reflections:reflections:0.9.10") implementation("dom4j:dom4j:1.6.1") + + // for inspecting modules + implementation("org.terasology:gestalt-module:5.1.5") // TODO: sync version w engine? } diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index a26218d1ff9..8306c45a47c 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -1,22 +1,8 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 // Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules -import groovy.json.JsonSlurper import org.gradle.plugins.ide.eclipse.model.EclipseModel import org.gradle.plugins.ide.idea.model.IdeaModel import org.reflections.Reflections @@ -24,7 +10,8 @@ import org.reflections.scanners.SubTypesScanner import org.reflections.scanners.TypeAnnotationsScanner import org.reflections.util.ConfigurationBuilder import org.reflections.util.FilterBuilder - +import org.terasology.module.ModuleMetadataJsonAdapter +import org.terasology.naming.Version plugins { id("java") @@ -43,7 +30,6 @@ val env by extra { System.getenv( )} // Alternatively one more round of refactoring could switch to Git tags, a single `master` branch, and possible other things to help match snaps/PR builds somehow? val bypassModuleReleaseManagement by extra("true") -val moduleDepends = mutableListOf() val moduleFile = file("module.txt") // The module file should always exist if the module was correctly created or cloned using Gradle @@ -52,39 +38,39 @@ if (!moduleFile.exists()) { throw GradleException("Failed to find module.txt for " + project.name) } -//println "Scanning for dependencies in module.txt for " + project.name -val slurper = JsonSlurper() // 😂 using groovy's json parser in kotlin -val moduleConfig: Map = slurper.parseText(moduleFile.readText())!! as Map -for (dependency in moduleConfig["dependencies"] as List>) { - if (dependency["id"] != "engine") { - moduleDepends.add(dependency["id"]!!) - } +val moduleConfig = moduleFile.reader().use { + ModuleMetadataJsonAdapter().read(it)!! } -// Gradle uses the magic version variable when creating the jar name (unless explicitly set somewhere else I guess) -version = moduleConfig["version"] as String +val moduleDepends : Collection = moduleConfig.dependencies.mapNotNull { + val name = it.id.toString() + if (name.toLowerCase() != "engine") { name } else { null } +} // Check for an outright -SNAPSHOT in the loaded version - for ease of use we want to get rid of that everywhere, so warn about it and remove for the variable -val undesiredSnapshotTag = version.toString().endsWith("-SNAPSHOT") -if (undesiredSnapshotTag) { - println("Taking off undesired -SNAPSHOT") - version = version.toString().removeSuffix("-SNAPSHOT") - println("WARNING: Module ${project.name} is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'") +if (moduleConfig.version.isSnapshot) { + logger.warn("Module ${project.name} is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'") + + moduleConfig.version = with(moduleConfig.version) { + Version(major, minor, patch, false) + } } // The only case in which we make module non-snapshots is if release management is enabled and BRANCH_NAME is "master" -if (moduleConfig["isReleaseManaged"].toString().toBoolean() && env["BRANCH_NAME"] == "master") { +val isReleaseManaged = moduleConfig.getExtension("isReleaseManaged", Boolean::class.java) ?: false +if (isReleaseManaged && env["BRANCH_NAME"] == "master") { // This is mildly awkward since we need to bypass by default, yet if release management is on (true) then we set the bypass to false .. val bypassModuleReleaseManagement by extra(false) } else { // In the case where we actually are building a snapshot we load -SNAPSHOT into the version variable, even if it wasn't there in module.txt - version = "${version}-SNAPSHOT" + moduleConfig.version = moduleConfig.version.snapshot } +project.version = moduleConfig.version // Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor -group = "org.terasology.modules" +project.group = "org.terasology.modules" -println("Version for $project.name loaded as $version for group $group") +logger.info("Version for {} loaded as {} for group {}", project.name, project.version, project.group) // Grab all the common stuff like plugins to use, artifact repositories, code analysis config, Artifactory settings, Git magic // Note that this statement is down a ways because it is affected by the stuff higher in this file like setting versioning From 8ff81036e969f7f46c9bc825389c540fa5e544c4 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 12:43:25 -0700 Subject: [PATCH 002/259] feat(build): use module.txt dependency versions when defining gradle dependencies --- .../main/kotlin/terasology-module.gradle.kts | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index 8306c45a47c..db096f3086a 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -42,11 +42,6 @@ val moduleConfig = moduleFile.reader().use { ModuleMetadataJsonAdapter().read(it)!! } -val moduleDepends : Collection = moduleConfig.dependencies.mapNotNull { - val name = it.id.toString() - if (name.toLowerCase() != "engine") { name } else { null } -} - // Check for an outright -SNAPSHOT in the loaded version - for ease of use we want to get rid of that everywhere, so warn about it and remove for the variable if (moduleConfig.version.isSnapshot) { logger.warn("Module ${project.name} is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'") @@ -93,14 +88,39 @@ configurations.all { resolutionStrategy.cacheChangingModulesFor(0, "seconds") } + +val deps = moduleConfig.dependencies.filterNotNull() +val moduleDepends = deps.filterNot { it.id.toString() == "engine" } +val engineVersion = deps.find { it.id.toString() == "engine" }?.versionRange()?.toString() ?: "+" + // Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules dependencies { // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace - implementation(group = "org.terasology.engine", name = "engine", version = "+") { isChanging = true } - implementation(group = "org.terasology.engine", name = "engine-tests", version = "+") { isChanging = true } + implementation(group = "org.terasology.engine", name = "engine", version = engineVersion) { isChanging = true } + implementation(group = "org.terasology.engine", name = "engine-tests", version = engineVersion) { isChanging = true } + + for (gestaltDep in moduleDepends) { + if (!gestaltDep.minVersion.isSnapshot) { + // gestalt considers snapshots to satisfy a minimum requirement: + // https://github.com/MovingBlocks/gestalt/blob/fe1893821127c254cd135252de2676eff31d0152/gestalt-module/src/main/java/org/terasology/naming/VersionRange.java#L58-L59 + gestaltDep.minVersion = gestaltDep.minVersion.snapshot + // (maybe there's some way to do that with a custom gradle resolver? + // but making a resolver that only works that way on gestalt modules specifically + // sounds complicated.) + } - for (dependency in moduleDepends) { - implementation(group = "org.terasology.modules", name = dependency, version = "+") { isChanging = true } + val gradleDep = create( + group = "org.terasology.modules", + name = gestaltDep.id.toString(), + version = gestaltDep.versionRange().toString() + ) + + if (gestaltDep.isOptional) { + // and/or testImplementation? + compileOnly(gradleDep) { isChanging = true } + } else { + implementation(gradleDep) { isChanging = true } + } } testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2") From 5b1902e7f0c30d9cfa17ae22f947eb5d3d3d5a36 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 14:07:09 -0700 Subject: [PATCH 003/259] fix(build): require module's "optional" dependencies while running their tests --- buildSrc/src/main/kotlin/terasology-module.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index db096f3086a..cd78e7cffa4 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -116,8 +116,12 @@ dependencies { ) if (gestaltDep.isOptional) { - // and/or testImplementation? + // `optional` module dependencies are ones it does not require for runtime + // (but will use opportunistically if available) compileOnly(gradleDep) { isChanging = true } + // though modules also sometimes use "optional" to describe their test dependencies; + // they're not required for runtime, but they *are* required for tests. + testImplementation(gradleDep) { isChanging = true } } else { implementation(gradleDep) { isChanging = true } } From f34bd09ecd75e04c7a74b44f0512a39d9c339ecd Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:44:27 -0700 Subject: [PATCH 004/259] chore: tidying up lint --- .idea/dictionaries/kevint.xml | 1 + buildSrc/src/main/kotlin/terasology-module.gradle.kts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.idea/dictionaries/kevint.xml b/.idea/dictionaries/kevint.xml index 063c0197a91..e6af065fa04 100644 --- a/.idea/dictionaries/kevint.xml +++ b/.idea/dictionaries/kevint.xml @@ -1,6 +1,7 @@ + artifactory gameplay minecraft reddit diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index cd78e7cffa4..2d4d6e4fb10 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -20,7 +20,7 @@ plugins { } // Read environment variables, including variables passed by jenkins continuous integration server -val env by extra { System.getenv( )} +val env: MutableMap by extra { System.getenv( )} // This is a fun one ... when versions switched to dynamic -SNAPSHOT or not based on branch existing modules using `master` would suddenly try publishing releases // This won't work without additionally doing constant version bumps (perhaps via Git tags) - but too much work to switch around all modules at once // Complicating things more the use of publish.gradle to centralize logic means modules and engine bits are treated the same, yet we need to vary modules @@ -81,7 +81,7 @@ configure { } } val convention = project.getConvention().getPlugin(JavaPluginConvention::class) -val mainSourceSet = convention.getSourceSets().getByName("main"); +val mainSourceSet = convention.getSourceSets().getByName("main") // TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins configurations.all { @@ -102,7 +102,7 @@ dependencies { for (gestaltDep in moduleDepends) { if (!gestaltDep.minVersion.isSnapshot) { // gestalt considers snapshots to satisfy a minimum requirement: - // https://github.com/MovingBlocks/gestalt/blob/fe1893821127c254cd135252de2676eff31d0152/gestalt-module/src/main/java/org/terasology/naming/VersionRange.java#L58-L59 + // https://github.com/MovingBlocks/gestalt/blob/fe1893821127/gestalt-module/src/main/java/org/terasology/naming/VersionRange.java#L58-L59 gestaltDep.minVersion = gestaltDep.minVersion.snapshot // (maybe there's some way to do that with a custom gradle resolver? // but making a resolver that only works that way on gestalt modules specifically @@ -192,7 +192,7 @@ tasks.register("cacheReflections") { .setScanners(TypeAnnotationsScanner(), SubTypesScanner())) reflections.save(outputs.getFiles().getAsPath()) } catch (e: java.net.MalformedURLException) { - getLogger().error("Cannot parse input to url", e); + logger.error("Cannot parse input to url", e) } } } From 0bc080e7c895d1934ea2bddbd300f4c10f4b4876 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:45:49 -0700 Subject: [PATCH 005/259] feat(build): better message on modules.txt errors, fixes #4018 --- .../main/kotlin/terasology-module.gradle.kts | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index 2d4d6e4fb10..70e693dffbe 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -38,8 +38,41 @@ if (!moduleFile.exists()) { throw GradleException("Failed to find module.txt for " + project.name) } -val moduleConfig = moduleFile.reader().use { - ModuleMetadataJsonAdapter().read(it)!! +class ModuleInfoException( + cause: Throwable, + @Suppress("MemberVisibilityCanBePrivate") val file: File? = null, + private val project: Project? = null +) : RuntimeException(cause) { + override val message: String + get() { + // trying to get the fully-qualified-class-name-mess off the front and just show + // the useful part. + val detail = cause?.cause?.localizedMessage ?: cause?.localizedMessage + return "Error while reading module info from ${describeFile()}:\n ${detail}" + } + + private fun describeFile(): String { + return if (project != null && file != null) { + project.rootProject.relativePath(file) + } else if (file != null) { + file.toString() + } else { + "[unnamed file]" + } + } + + override fun toString(): String { + val causeType = cause?.let { it::class.simpleName } + return "ModuleInfoException(file=${describeFile()}, cause=${causeType})" + } +} + +val moduleConfig = try { + moduleFile.reader().use { + ModuleMetadataJsonAdapter().read(it)!! + } +} catch (e: Exception) { + throw ModuleInfoException(e, moduleFile, project) } // Check for an outright -SNAPSHOT in the loaded version - for ease of use we want to get rid of that everywhere, so warn about it and remove for the variable From ad12d4063955b0cb3550c3fcf74375763fd3815d Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:57:46 -0700 Subject: [PATCH 006/259] chore(build): use map-syntax for these extra props that are only accessed from other scopes otherwise kotlin warns they are unused --- buildSrc/src/main/kotlin/terasology-module.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index 70e693dffbe..e2e8899b8f2 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -28,7 +28,7 @@ val env: MutableMap by extra { System.getenv( )} // If a module actually wants release management simply include `"isReleaseManaged" : true` in module.txt - this is needed for the engine repo embedded modules // One option would be to slowly convert modulespace to default to a `develop` + `master` setup living in harmony with associated automation/github tweaks // Alternatively one more round of refactoring could switch to Git tags, a single `master` branch, and possible other things to help match snaps/PR builds somehow? -val bypassModuleReleaseManagement by extra("true") +extra["bypassModuleReleaseManagement"] = true val moduleFile = file("module.txt") @@ -88,7 +88,7 @@ if (moduleConfig.version.isSnapshot) { val isReleaseManaged = moduleConfig.getExtension("isReleaseManaged", Boolean::class.java) ?: false if (isReleaseManaged && env["BRANCH_NAME"] == "master") { // This is mildly awkward since we need to bypass by default, yet if release management is on (true) then we set the bypass to false .. - val bypassModuleReleaseManagement by extra(false) + extra["bypassModuleReleaseManagement"] = false } else { // In the case where we actually are building a snapshot we load -SNAPSHOT into the version variable, even if it wasn't there in module.txt moduleConfig.version = moduleConfig.version.snapshot From 5de29be01ddbf5663a3c733c28cf039b07d2e0a7 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 6 Jun 2020 18:09:22 -0700 Subject: [PATCH 007/259] feat(build): use version as given from version.txt instead of adding -SNAPSHOT based on git branch fixes #4037 --- .../main/kotlin/terasology-module.gradle.kts | 29 ---------------- config/gradle/publish.gradle | 34 +++---------------- 2 files changed, 5 insertions(+), 58 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index e2e8899b8f2..bae8d04116c 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -11,7 +11,6 @@ import org.reflections.scanners.TypeAnnotationsScanner import org.reflections.util.ConfigurationBuilder import org.reflections.util.FilterBuilder import org.terasology.module.ModuleMetadataJsonAdapter -import org.terasology.naming.Version plugins { id("java") @@ -21,14 +20,6 @@ plugins { // Read environment variables, including variables passed by jenkins continuous integration server val env: MutableMap by extra { System.getenv( )} -// This is a fun one ... when versions switched to dynamic -SNAPSHOT or not based on branch existing modules using `master` would suddenly try publishing releases -// This won't work without additionally doing constant version bumps (perhaps via Git tags) - but too much work to switch around all modules at once -// Complicating things more the use of publish.gradle to centralize logic means modules and engine bits are treated the same, yet we need to vary modules -// Temporary workaround: default modules to bypass release management: master branch builds will still make snapshot builds for the snapshot repo -// If a module actually wants release management simply include `"isReleaseManaged" : true` in module.txt - this is needed for the engine repo embedded modules -// One option would be to slowly convert modulespace to default to a `develop` + `master` setup living in harmony with associated automation/github tweaks -// Alternatively one more round of refactoring could switch to Git tags, a single `master` branch, and possible other things to help match snaps/PR builds somehow? -extra["bypassModuleReleaseManagement"] = true val moduleFile = file("module.txt") @@ -75,25 +66,6 @@ val moduleConfig = try { throw ModuleInfoException(e, moduleFile, project) } -// Check for an outright -SNAPSHOT in the loaded version - for ease of use we want to get rid of that everywhere, so warn about it and remove for the variable -if (moduleConfig.version.isSnapshot) { - logger.warn("Module ${project.name} is explicitly versioned as a snapshot in module.txt, please remove '-SNAPSHOT'") - - moduleConfig.version = with(moduleConfig.version) { - Version(major, minor, patch, false) - } -} - -// The only case in which we make module non-snapshots is if release management is enabled and BRANCH_NAME is "master" -val isReleaseManaged = moduleConfig.getExtension("isReleaseManaged", Boolean::class.java) ?: false -if (isReleaseManaged && env["BRANCH_NAME"] == "master") { - // This is mildly awkward since we need to bypass by default, yet if release management is on (true) then we set the bypass to false .. - extra["bypassModuleReleaseManagement"] = false -} else { - // In the case where we actually are building a snapshot we load -SNAPSHOT into the version variable, even if it wasn't there in module.txt - moduleConfig.version = moduleConfig.version.snapshot -} - project.version = moduleConfig.version // Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor project.group = "org.terasology.modules" @@ -128,7 +100,6 @@ val engineVersion = deps.find { it.id.toString() == "engine" }?.versionRange()?. // Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules dependencies { - // Check to see if this module is not the root Gradle project - if so we are in a multi-project workspace implementation(group = "org.terasology.engine", name = "engine", version = engineVersion) { isChanging = true } implementation(group = "org.terasology.engine", name = "engine-tests", version = engineVersion) { isChanging = true } diff --git a/config/gradle/publish.gradle b/config/gradle/publish.gradle index d3ef0698907..20c5b212bfa 100644 --- a/config/gradle/publish.gradle +++ b/config/gradle/publish.gradle @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 // This include file applies maven-publish related settings to places that need them (root project + modules) // It is a superset of the the stuff common to Java sub projects so we include the common.gradle here @@ -46,12 +33,10 @@ publishing { deducedPublishRepo = "terasology" } - // Check the active Git branch and some module logic to see whether we're doing a release or snapshot - String gitBranch = System.getenv()["BRANCH_NAME"] - if (isMaster(gitBranch) && !shouldBypassModuleRelease()) { - deducedPublishRepo += "-release-local" - } else { + if (project.version.toString().endsWith("-SNAPSHOT")) { deducedPublishRepo += "-snapshot-local" + } else { + deducedPublishRepo += "-release-local" } logger.info("The final deduced publish repo is {}", deducedPublishRepo) @@ -73,12 +58,3 @@ publishing { } } } - -static def isMaster(gitBranch) { - return gitBranch != null && gitBranch.equals("master"); -} - -// Mildly awkward: Modules aren't ready globally to accept master branch == release, so make it opt-in by checking a prop that defaults to bypass -def shouldBypassModuleRelease() { - return project.hasProperty("bypassModuleReleaseManagement") && bypassModuleReleaseManagement == "true"; -} From ab028b2d5a8557b351e1c9a10ff051640ca8d176 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 6 Jun 2020 18:54:03 -0700 Subject: [PATCH 008/259] chore: remove unused variable --- buildSrc/src/main/kotlin/terasology-module.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index bae8d04116c..f57ff952046 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -18,9 +18,6 @@ plugins { id("eclipse") } -// Read environment variables, including variables passed by jenkins continuous integration server -val env: MutableMap by extra { System.getenv( )} - val moduleFile = file("module.txt") // The module file should always exist if the module was correctly created or cloned using Gradle From bbac516c908bdf46f8b936476651d30247c7e54f Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 21 Aug 2020 12:56:38 -0700 Subject: [PATCH 009/259] chore(gradle): update idea-ext gradle plugin to 0.8.1 not specific to this branch, just something I tried to fix gradle import errors. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 55887909244..2810dc5879a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ plugins { //apply plugin: 'eclipse' id "idea" // For the "Build and run using: Intellij IDEA | Gradle" switch - id "org.jetbrains.gradle.plugin.idea-ext" version "0.7" + id "org.jetbrains.gradle.plugin.idea-ext" version "0.8.1" } From d046341abd431c80fc64ba4a6653bbae1c14d16a Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 21 Aug 2020 13:07:20 -0700 Subject: [PATCH 010/259] fix(gradle): don't force all dependencies to be "changing" Dependencies pulled from maven repositories with `-SNAPSHOT` versions are implicitly treated as changing without need for this override. --- buildSrc/src/main/kotlin/terasology-module.gradle.kts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index f57ff952046..0cd4619e370 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -97,8 +97,8 @@ val engineVersion = deps.find { it.id.toString() == "engine" }?.versionRange()?. // Set dependencies. Note that the dependency information from module.txt is used for other Terasology modules dependencies { - implementation(group = "org.terasology.engine", name = "engine", version = engineVersion) { isChanging = true } - implementation(group = "org.terasology.engine", name = "engine-tests", version = engineVersion) { isChanging = true } + implementation(group = "org.terasology.engine", name = "engine", version = engineVersion) + implementation(group = "org.terasology.engine", name = "engine-tests", version = engineVersion) for (gestaltDep in moduleDepends) { if (!gestaltDep.minVersion.isSnapshot) { @@ -119,12 +119,12 @@ dependencies { if (gestaltDep.isOptional) { // `optional` module dependencies are ones it does not require for runtime // (but will use opportunistically if available) - compileOnly(gradleDep) { isChanging = true } + compileOnly(gradleDep) // though modules also sometimes use "optional" to describe their test dependencies; // they're not required for runtime, but they *are* required for tests. - testImplementation(gradleDep) { isChanging = true } + testImplementation(gradleDep) } else { - implementation(gradleDep) { isChanging = true } + implementation(gradleDep) } } From 93b62d02b21129e8b6565501978fc378e1e95bff Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 21 Aug 2020 13:32:14 -0700 Subject: [PATCH 011/259] fix(gradle): rely on engine-module.txt to tell us if the version is a snapshot for consistency with other modules. --- engine/build.gradle | 5 ----- engine/src/main/resources/engine-module.txt | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index db28867281a..3a3651a44c9 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -212,11 +212,6 @@ def moduleConfig = slurper.parseText(moduleFile.text) // Gradle uses the magic version variable when creating the jar name (unless explicitly set differently) version = moduleConfig.version -// The only case in which we make non-snapshots is when BRANCH_NAME exists and contains "master" - otherwise snapshots -if (env.BRANCH_NAME == null || !env.BRANCH_NAME.equals("master")) { - version += "-SNAPSHOT" -} - // Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor group = 'org.terasology.engine' diff --git a/engine/src/main/resources/engine-module.txt b/engine/src/main/resources/engine-module.txt index 7105a20cc7e..82c8f4ee54e 100644 --- a/engine/src/main/resources/engine-module.txt +++ b/engine/src/main/resources/engine-module.txt @@ -1,6 +1,6 @@ { "id" : "engine", - "version" : "3.3.0", + "version" : "3.4.0-SNAPSHOT", "displayName" : "Terasology Engine", "description" : "Core engine content" } From 1e774d9924949ad1bcdf7e4e18c97462d7d60d6a Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 14 Nov 2020 17:00:36 -0800 Subject: [PATCH 012/259] chore (git): ignore .idea/caches --- .idea/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.idea/.gitignore b/.idea/.gitignore index 063180a3c14..54bad757e64 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -5,6 +5,8 @@ workspace.xml *.iws +/caches + # Shelf is where it put changes you're not ready to share. (it's like git stash) /shelf From 791987d9e3030804257fc522626de78ec535c5e7 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 14 Nov 2020 17:26:35 -0800 Subject: [PATCH 013/259] chore (build): stop overriding the module cache lifetime See discussion in https://github.com/MovingBlocks/Terasology/pull/4039#issuecomment-678582262 --- build.gradle | 6 ------ buildSrc/src/main/kotlin/terasology-module.gradle.kts | 5 ----- engine/build.gradle | 5 ----- 3 files changed, 16 deletions(-) diff --git a/build.gradle b/build.gradle index c571694ab87..f2831d6a9cc 100644 --- a/build.gradle +++ b/build.gradle @@ -203,12 +203,6 @@ gradle.projectsEvaluated { moduleJars.dependsOn(terasologyModules().jar) } -// This is a TEMPORARY tweak to make "changing" dependencies always ('0') check for newer snapshots available -// TODO: Remove this when versioning and promotion works fully, then we shouldn't care about snapshots normally anyway -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - // Include deletion of extracted natives in the global clean task. Without the doLast it runs on *every* execution ... clean.doLast { new File(dirNatives).deleteDir() diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index 0cd4619e370..3a03c9a96b8 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -85,11 +85,6 @@ configure { val convention = project.getConvention().getPlugin(JavaPluginConvention::class) val mainSourceSet = convention.getSourceSets().getByName("main") -// TODO: Remove when we don't need to rely on snapshots. Needed here for solo builds in Jenkins -configurations.all { - resolutionStrategy.cacheChangingModulesFor(0, "seconds") -} - val deps = moduleConfig.dependencies.filterNotNull() val moduleDepends = deps.filterNot { it.id.toString() == "engine" } diff --git a/engine/build.gradle b/engine/build.gradle index 25f54956ae6..9c46f70a4e7 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -71,11 +71,6 @@ configurations { } } -// TODO: Remove when we don't need to rely on snapshots. Wonder why modules respected this set in root project, engine not so much -configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - // Primary dependencies definition dependencies { // Storage and networking From 3db59b7fa9ad4d6b90cdfa1745e5415ad6f21055 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 14 Nov 2020 17:33:34 -0800 Subject: [PATCH 014/259] chore (build): remove stray comment don't worry about putting extra work into syncing the versions among subprojects. I think the depenecy resolver will work it out. --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index d6c609a400d..8c014a97deb 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,5 +24,5 @@ dependencies { implementation("dom4j:dom4j:1.6.1") // for inspecting modules - implementation("org.terasology:gestalt-module:5.1.5") // TODO: sync version w engine? + implementation("org.terasology:gestalt-module:5.1.5") } From 6641713be9ff64cd248d60dd677dc4a358ea9073 Mon Sep 17 00:00:00 2001 From: Josephine Rueckert Date: Sun, 6 Dec 2020 19:51:41 +0100 Subject: [PATCH 015/259] chore: prepare snapshot builds for 4.2.0 --- engine-tests/src/main/resources/module.txt | 2 +- engine/src/main/resources/engine-module.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine-tests/src/main/resources/module.txt b/engine-tests/src/main/resources/module.txt index 5c5f5e7c28c..5a260407750 100644 --- a/engine-tests/src/main/resources/module.txt +++ b/engine-tests/src/main/resources/module.txt @@ -1,6 +1,6 @@ { "id" : "unittest", - "version" : "4.1.0", + "version" : "4.2.0-SNAPSHOT", "displayName" : "Terasology Engine Test", "description" : "Engine unit test content" } diff --git a/engine/src/main/resources/engine-module.txt b/engine/src/main/resources/engine-module.txt index bc5f451cfbf..120406d808d 100644 --- a/engine/src/main/resources/engine-module.txt +++ b/engine/src/main/resources/engine-module.txt @@ -1,6 +1,6 @@ { "id" : "engine", - "version" : "4.1.0", + "version" : "4.2.0-SNAPSHOT", "displayName" : "Terasology Engine", "description" : "Core engine content" } From fabfe79b34f9207a9ccde20e05079a40e30da471 Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Tue, 8 Dec 2020 11:38:27 +0300 Subject: [PATCH 016/259] feat(subsystems): extract TypeHandlerLibrary. (#4255) * build(subsystems): fix manifest's classpath gatherning in buildscript time. (locked cache) * feat(TypeHandlerLibrary): add PersistentDataArray implementations of `in-memory` * feat(TypeHandlerLibrary): move most part of code from TypeHandlerLibraryImpl * feat(TypeHandlerLibrary): split TypeHandlerLibraryTest and setup default handlers correctly * feat(TypeHandlerLibrary): move `ConstructorLibrary`, `CollectionTypeHandlerFactory`, `OjbectFiledMapTypeHandlerFactory` and they tests to `TypeHandlerWidget` subsystem. * test(TypeHandlerLibrary): move tests from engine to TypEHandlerLibrary subsystem * test(TypeHandlerLibrary): add tests for simple type handlers and byte/bytes type handlers * test(TypeHandlerLibrary): add Test for In-memory persistent * chore(subsystems): replace copyrigh with 2 line copyright * chore(TypeHandlerLibrary): remove public modifiers for tests (sonarlint - junit 5 issue) * chore(TypeHandlerLibrary): make fields private for TypeHandlerLibrary * perf(TypeHandlerLibrary): replace mock with implementation in CharacterTypeHandlerTest * fix(TypeHandlerLibrary): change method reference for typeHandlerLibrary.populateBuiltInHandlers * fix(TypeHandlerLibrary): move `AbstractSerializer` to TWL subsystem. --- .../flexible/AutoConfigSerializerTest.java | 20 +- .../entitySystem/PojoEventSystemTests.java | 21 +- .../entitySystem/PojoPrefabManagerTest.java | 20 +- .../terasology/entitySystem/PrefabTest.java | 17 +- .../metadata/ComponentMetadataTest.java | 24 +- .../persistence/ComponentSerializerTest.java | 21 +- .../serializers/TypeSerializerTest.java | 20 +- .../serializers/VectorTypeSerializerTest.java | 20 +- .../event/VectorEventSerializer.java | 8 +- ...nTypeHandlerLibraryAdapterFactoryTest.java | 20 +- .../mathTypes/AABBTypeHandlerTest.java | 3 +- .../mathTypes/BlockRegionTypeHandlerTest.java | 3 +- .../recording/EventSystemReplayImplTest.java | 3 +- engine/build.gradle | 14 +- .../terasology/engine/TerasologyEngine.java | 3 +- .../bootstrap/EntitySystemSetupUtil.java | 20 +- .../bootstrap/EnvironmentSwitchHandler.java | 21 +- .../network/internal/NetworkSystemImpl.java | 2 +- .../DeserializationException.java | 39 -- .../typeHandling/SerializationException.java | 39 -- .../typeHandling/TypeHandlerLibrary.java | 485 ---------------- .../typeHandling/TypeHandlerLibraryImpl.java | 162 ++++++ .../annotations/SerializedName.java | 34 -- .../inMemory/PersistedBoolean.java | 36 -- .../inMemory/PersistedDouble.java | 46 -- .../typeHandling/inMemory/PersistedFloat.java | 47 -- .../inMemory/PersistedInteger.java | 46 -- .../typeHandling/inMemory/PersistedLong.java | 46 -- .../inMemory/PersistedNumber.java | 38 -- .../inMemory/PersistedString.java | 38 -- .../typeHandling/package-info.java | 24 - .../recording/RecordedEventSerializer.java | 20 +- .../rendering/nui/asset/UIFormat.java | 29 +- subsystems/TypeHandlerLibrary/README.MD | 72 +++ .../TypeHandlerLibrary/build.gradle.kts | 25 + .../serializers/AbstractSerializer.java | 0 .../serializers/DeserializeFieldCheck.java | 17 +- .../DeserializationException.java | 26 + .../typeHandling/FutureTypeHandler.java | 17 +- .../typeHandling/InstanceCreator.java | 17 +- .../typeHandling/PersistedData.java | 19 +- .../typeHandling/PersistedDataArray.java | 17 +- .../typeHandling/PersistedDataMap.java | 17 +- .../typeHandling/PersistedDataSerializer.java | 17 +- .../typeHandling/SerializationException.java | 26 + .../persistence/typeHandling/Serializer.java | 17 +- .../SpecificTypeHandlerFactory.java | 17 +- .../StringRepresentationTypeHandler.java | 17 +- .../persistence/typeHandling/TypeHandler.java | 17 +- .../typeHandling/TypeHandlerContext.java | 17 +- .../typeHandling/TypeHandlerFactory.java | 17 +- .../typeHandling/TypeHandlerLibrary.java | 327 +++++++++++ .../annotations/SerializedName.java | 21 + .../coreTypes/ArrayTypeHandler.java | 17 +- .../coreTypes/BooleanTypeHandler.java | 17 +- .../coreTypes/ByteArrayTypeHandler.java | 17 +- .../coreTypes/ByteTypeHandler.java | 17 +- .../coreTypes/CharacterTypeHandler.java | 17 +- .../coreTypes/CollectionTypeHandler.java | 17 +- .../coreTypes/DoubleTypeHandler.java | 17 +- .../coreTypes/EnumTypeHandler.java | 17 +- .../coreTypes/FloatTypeHandler.java | 17 +- .../coreTypes/IntTypeHandler.java | 17 +- .../coreTypes/LongTypeHandler.java | 17 +- .../coreTypes/NumberTypeHandler.java | 17 +- .../coreTypes/ObjectFieldMapTypeHandler.java | 17 +- .../RuntimeDelegatingTypeHandler.java | 19 +- .../coreTypes/StringMapTypeHandler.java | 17 +- .../coreTypes/StringTypeHandler.java | 17 +- .../factories/ArrayTypeHandlerFactory.java | 19 +- .../CollectionTypeHandlerFactory.java | 21 +- .../factories/EnumTypeHandlerFactory.java | 19 +- .../ObjectFieldMapTypeHandlerFactory.java | 21 +- .../StringMapTypeHandlerFactory.java | 21 +- .../inMemory/AbstractPersistedData.java | 17 +- .../InMemoryPersistedDataSerializer.java | 168 ++++++ .../inMemory/PersistedBoolean.java | 23 + .../typeHandling/inMemory/PersistedBytes.java | 30 + .../inMemory/PersistedDouble.java | 33 ++ .../typeHandling/inMemory/PersistedFloat.java | 34 ++ .../inMemory/PersistedInteger.java | 33 ++ .../typeHandling/inMemory/PersistedLong.java | 33 ++ .../typeHandling/inMemory/PersistedMap.java | 17 +- .../inMemory/PersistedNumber.java | 25 + .../inMemory/PersistedString.java | 25 + .../arrays/AbstractPersistedArray.java | 78 +++ .../arrays/PersistedBooleanArray.java | 58 ++ .../inMemory/arrays/PersistedDoubleArray.java | 63 ++ .../inMemory/arrays/PersistedFloatArray.java | 62 ++ .../arrays/PersistedIntegerArray.java | 62 ++ .../inMemory/arrays/PersistedLongArray.java | 62 ++ .../inMemory/arrays/PersistedNumberArray.java | 47 ++ .../inMemory/arrays/PersistedStringArray.java | 55 ++ .../inMemory/arrays/PersistedValueArray.java | 144 +++++ .../inMemory/arrays/TroveUtils.java | 228 ++++++++ .../typeHandling/package-info.java | 11 + .../reflection/ReflectionsSandbox.java | 12 + .../reflection/SerializationSandbox.java | 0 .../reflect/ConstructorLibrary.java | 20 +- .../typeHandling/FutureTypeHandlerTest.java | 21 +- .../typeHandling/InMemorySerializerTest.java | 536 ++++++++++++++++++ .../typeHandling/TypeHandlerLibraryTest.java | 59 +- .../coreTypes/ArrayTypeHandlerTest.java | 36 +- .../coreTypes/CharacterTypeHandlerTest.java | 35 +- .../coreTypes/CollectionTypeHandlerTest.java | 36 +- .../EnumTypeHandlerSerializerTest.java | 25 +- .../RuntimeDelegatingTypeHandlerTest.java | 29 +- .../coreTypes/SimpleCoreHandlerTest.java | 68 +++ .../ArrayTypeHandlerFactoryTest.java | 25 +- .../factories/BytesTypeHandlerTest.java | 56 ++ .../CollectionTypeHandlerFactoryTest.java | 17 +- .../factories/EnumTypeHandlerFactoryTest.java | 23 +- .../ObjectFieldMapTypeHandlerFactoryTest.java | 17 +- .../StringMapTypeHandlerFactoryTest.java | 25 +- 114 files changed, 2865 insertions(+), 1967 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java create mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java delete mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/package-info.java create mode 100644 subsystems/TypeHandlerLibrary/README.MD create mode 100644 subsystems/TypeHandlerLibrary/build.gradle.kts rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/serializers/AbstractSerializer.java (100%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java (60%) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java (60%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java (59%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java (84%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java (56%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java (86%) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/Serializer.java (90%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java (66%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java (87%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java (68%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java (70%) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java (79%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java (55%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java (58%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java (60%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java (73%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java (72%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java (54%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java (55%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java (87%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java (93%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java (73%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java (55%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java (75%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java (79%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java (64%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java (85%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java (75%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java (78%) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/InMemoryPersistedDataSerializer.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBytes.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java (75%) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/AbstractPersistedArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedBooleanArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedDoubleArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedFloatArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedIntegerArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedLongArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedNumberArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedStringArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedValueArray.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/TroveUtils.java create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/package-info.java rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java (77%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/persistence/typeHandling/reflection/SerializationSandbox.java (100%) rename {engine => subsystems/TypeHandlerLibrary}/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java (91%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java (78%) create mode 100644 subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/InMemorySerializerTest.java rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java (71%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java (63%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java (50%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java (68%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java (70%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java (89%) create mode 100644 subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/SimpleCoreHandlerTest.java rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java (76%) create mode 100644 subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/BytesTypeHandlerTest.java rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java (85%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java (63%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java (77%) rename {engine-tests => subsystems/TypeHandlerLibrary}/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java (76%) diff --git a/engine-tests/src/test/java/org/terasology/config/flexible/AutoConfigSerializerTest.java b/engine-tests/src/test/java/org/terasology/config/flexible/AutoConfigSerializerTest.java index 1b34cb5383d..d901aa8e95a 100644 --- a/engine-tests/src/test/java/org/terasology/config/flexible/AutoConfigSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/config/flexible/AutoConfigSerializerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2019 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.config.flexible; import com.google.common.collect.ImmutableList; @@ -22,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; @@ -37,7 +25,7 @@ public class AutoConfigSerializerTest { @BeforeEach public void setup() { - TypeHandlerLibrary library = TypeHandlerLibrary.withReflections(mock(Reflections.class)); + TypeHandlerLibrary library = TypeHandlerLibraryImpl.withReflections(mock(Reflections.class)); autoConfigSerializer = new AutoConfigSerializer<>(TestAutoConfig.class, library); } diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/PojoEventSystemTests.java b/engine-tests/src/test/java/org/terasology/entitySystem/PojoEventSystemTests.java index ea4df558d8d..81c1999b912 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/PojoEventSystemTests.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/PojoEventSystemTests.java @@ -1,25 +1,11 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.entitySystem; import com.google.common.collect.Lists; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.reflections.Reflections; -import org.terasology.assets.ResourceUrn; import org.terasology.context.internal.ContextImpl; import org.terasology.engine.SimpleUri; import org.terasology.entitySystem.entity.EntityRef; @@ -39,6 +25,7 @@ import org.terasology.network.NetworkMode; import org.terasology.network.NetworkSystem; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.recording.EventCatcher; import org.terasology.recording.RecordAndReplayCurrentStatus; import org.terasology.registry.CoreRegistry; @@ -65,7 +52,7 @@ public void setup() { CoreRegistry.setContext(context); Reflections reflections = new Reflections(getClass().getClassLoader()); - TypeHandlerLibrary serializationLibrary = new TypeHandlerLibrary(reflections); + TypeHandlerLibrary serializationLibrary = new TypeHandlerLibraryImpl(reflections); EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, serializationLibrary); compLibrary = entitySystemLibrary.getComponentLibrary(); diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java b/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java index 983935ce41c..7e7968c2ec0 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.entitySystem; import org.junit.jupiter.api.BeforeEach; @@ -34,6 +21,7 @@ import org.terasology.math.geom.Quat4f; import org.terasology.math.geom.Vector3f; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyQuat4fTypeHandler; import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3fTypeHandler; import org.terasology.registry.CoreRegistry; @@ -60,7 +48,7 @@ public void setup() throws Exception { ModuleManager moduleManager = ModuleManagerFactory.create(); Reflections reflections = new Reflections(getClass().getClassLoader()); - TypeHandlerLibrary lib = new TypeHandlerLibrary(reflections); + TypeHandlerLibrary lib = new TypeHandlerLibraryImpl(reflections); lib.addTypeHandler(Vector3f.class, new LegacyVector3fTypeHandler()); lib.addTypeHandler(Quat4f.class, new LegacyQuat4fTypeHandler()); diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/PrefabTest.java b/engine-tests/src/test/java/org/terasology/entitySystem/PrefabTest.java index f6e895d7b98..2aaf4041858 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/PrefabTest.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/PrefabTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.entitySystem; import org.junit.jupiter.api.BeforeEach; diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/metadata/ComponentMetadataTest.java b/engine-tests/src/test/java/org/terasology/entitySystem/metadata/ComponentMetadataTest.java index 3f440ea6129..183eb9b9bb5 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/metadata/ComponentMetadataTest.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/metadata/ComponentMetadataTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.entitySystem.metadata; @@ -22,10 +9,9 @@ import org.terasology.assets.ResourceUrn; import org.terasology.context.Context; import org.terasology.context.internal.ContextImpl; -import org.terasology.engine.SimpleUri; import org.terasology.entitySystem.stubs.OwnerComponent; import org.terasology.entitySystem.stubs.StringComponent; -import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.reflection.copy.CopyStrategyLibrary; import org.terasology.reflection.reflect.ReflectFactory; import org.terasology.reflection.reflect.ReflectionReflectFactory; @@ -51,7 +37,7 @@ public void prepare() { @Test public void testStaticFieldsIgnored() { Reflections reflections = new Reflections(getClass().getClassLoader()); - EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, new TypeHandlerLibrary(reflections)); + EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, new TypeHandlerLibraryImpl(reflections)); ComponentLibrary lib = entitySystemLibrary.getComponentLibrary(); lib.register(new ResourceUrn("unittest:string"), StringComponent.class); ComponentMetadata metadata = lib.getMetadata(StringComponent.class); @@ -61,7 +47,7 @@ public void testStaticFieldsIgnored() { @Test public void testOwnsReferencesPopulated() { Reflections reflections = new Reflections(getClass().getClassLoader()); - EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, new TypeHandlerLibrary(reflections)); + EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, new TypeHandlerLibraryImpl(reflections)); ComponentLibrary lib = entitySystemLibrary.getComponentLibrary(); lib.register(new ResourceUrn("unittest:owner"), OwnerComponent.class); ComponentMetadata metadata = lib.getMetadata(OwnerComponent.class); diff --git a/engine-tests/src/test/java/org/terasology/persistence/ComponentSerializerTest.java b/engine-tests/src/test/java/org/terasology/persistence/ComponentSerializerTest.java index 6b721bc3220..a77c961218d 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/ComponentSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/ComponentSerializerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence; import com.google.common.collect.ImmutableMap; @@ -23,7 +10,6 @@ import org.terasology.assets.ResourceUrn; import org.terasology.context.Context; import org.terasology.context.internal.ContextImpl; -import org.terasology.engine.SimpleUri; import org.terasology.engine.bootstrap.EntitySystemSetupUtil; import org.terasology.engine.module.ModuleManager; import org.terasology.entitySystem.Component; @@ -37,6 +23,7 @@ import org.terasology.network.NetworkSystem; import org.terasology.persistence.serializers.ComponentSerializer; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyQuat4fTypeHandler; import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3fTypeHandler; import org.terasology.protobuf.EntityData; @@ -69,7 +56,7 @@ public void setup() { CoreRegistry.setContext(context); Reflections reflections = new Reflections(getClass().getClassLoader()); - TypeHandlerLibrary serializationLibrary = new TypeHandlerLibrary(reflections); + TypeHandlerLibrary serializationLibrary = new TypeHandlerLibraryImpl(reflections); serializationLibrary.addTypeHandler(Vector3f.class, new LegacyVector3fTypeHandler()); serializationLibrary.addTypeHandler(Quat4f.class, new LegacyQuat4fTypeHandler()); diff --git a/engine-tests/src/test/java/org/terasology/persistence/serializers/TypeSerializerTest.java b/engine-tests/src/test/java/org/terasology/persistence/serializers/TypeSerializerTest.java index 8a1ff66e89a..e316397817b 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/serializers/TypeSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/serializers/TypeSerializerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.serializers; import com.google.common.collect.Lists; @@ -24,6 +11,7 @@ import org.terasology.nui.Color; import org.terasology.persistence.ModuleContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.annotations.SerializedName; import org.terasology.reflection.TypeInfo; @@ -54,7 +42,7 @@ public class TypeSerializerTest extends ModuleEnvironmentTest { public void setup() { ModuleContext.setContext(moduleManager.getEnvironment().get(new Name("unittest"))); - typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry); + typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); protobufSerializer = new ProtobufSerializer(typeHandlerLibrary); gsonSerializer = new GsonSerializer(typeHandlerLibrary); diff --git a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java index 02c65b8838c..fcfc9c8254c 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.serializers; import org.joml.Vector2fc; @@ -26,6 +13,7 @@ import org.terasology.naming.Name; import org.terasology.persistence.ModuleContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.reflection.TypeInfo; import org.terasology.testUtil.TeraAssert; @@ -61,7 +49,7 @@ static class TestObject2 { public void setup() { ModuleContext.setContext(moduleManager.getEnvironment().get(new Name("unittest"))); - typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry); + typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); protobufSerializer = new ProtobufSerializer(typeHandlerLibrary); gsonSerializer = new GsonSerializer(typeHandlerLibrary); diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java index 456387ea810..6d917b475e0 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java @@ -11,19 +11,15 @@ import org.joml.Vector4fc; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.reflections.Reflections; -import org.terasology.ModuleEnvironmentTest; import org.terasology.assets.ResourceUrn; import org.terasology.context.internal.ContextImpl; -import org.terasology.engine.SimpleUri; import org.terasology.engine.module.ModuleManager; import org.terasology.entitySystem.event.Event; import org.terasology.entitySystem.metadata.EntitySystemLibrary; import org.terasology.entitySystem.metadata.EventMetadata; -import org.terasology.naming.Name; -import org.terasology.persistence.ModuleContext; import org.terasology.persistence.serializers.EventSerializer; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.protobuf.EntityData; import org.terasology.reflection.TypeRegistry; import org.terasology.reflection.copy.CopyStrategyLibrary; @@ -69,7 +65,7 @@ public void setup() throws Exception { context.put(CopyStrategyLibrary.class, copyStrategies); TypeRegistry typeRegistry = new TypeRegistry(moduleManager.getEnvironment()); - TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry); + TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); entitySystemLibrary = new EntitySystemLibrary(context, typeHandlerLibrary); diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerLibraryAdapterFactoryTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerLibraryAdapterFactoryTest.java index a7535dbc963..adac0ed761c 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerLibraryAdapterFactoryTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerLibraryAdapterFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.gson; import com.google.common.collect.ImmutableMap; @@ -24,6 +11,7 @@ import org.terasology.math.geom.Vector4f; import org.terasology.nui.Color; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import java.util.Map; import java.util.Objects; @@ -49,7 +37,7 @@ public class GsonTypeHandlerLibraryAdapterFactoryTest { private final Reflections reflections = new Reflections(getClass().getClassLoader()); private final TypeHandlerLibrary typeHandlerLibrary = - TypeHandlerLibrary.withReflections(reflections); + TypeHandlerLibraryImpl.withReflections(reflections); private final Gson gson = GsonBuilderFactory.createGsonBuilderWithTypeSerializationLibrary(typeHandlerLibrary) diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java index 135afaca1b7..3c92e1b0097 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java @@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.gson.GsonBuilderFactory; public class AABBTypeHandlerTest extends MathTypeAssert { @@ -30,7 +31,7 @@ public static class AABB3Test { } private final Reflections reflections = new Reflections(getClass().getClassLoader()); - private final TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.withReflections(reflections); + private final TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.withReflections(reflections); private AABBiTypeHandler handler = new AABBiTypeHandler(); private final Gson gson = diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java index f2711a31469..a4820825462 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.gson.GsonBuilderFactory; import org.terasology.world.block.BlockRegion; @@ -21,7 +22,7 @@ public static class AABBBlockRegion1Test { } private final Reflections reflections = new Reflections(getClass().getClassLoader()); - private final TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.withReflections(reflections); + private final TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.withReflections(reflections); private AABBiTypeHandler handler = new AABBiTypeHandler(); private final Gson gson = diff --git a/engine-tests/src/test/java/org/terasology/recording/EventSystemReplayImplTest.java b/engine-tests/src/test/java/org/terasology/recording/EventSystemReplayImplTest.java index bfd203173a1..7f3e2be0b94 100644 --- a/engine-tests/src/test/java/org/terasology/recording/EventSystemReplayImplTest.java +++ b/engine-tests/src/test/java/org/terasology/recording/EventSystemReplayImplTest.java @@ -25,6 +25,7 @@ import org.terasology.network.NetworkMode; import org.terasology.network.NetworkSystem; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.reflection.TypeRegistry; import org.terasology.registry.CoreRegistry; @@ -48,7 +49,7 @@ public void setup() { CoreRegistry.setContext(context); Reflections reflections = new Reflections(getClass().getClassLoader()); - TypeHandlerLibrary serializationLibrary = new TypeHandlerLibrary(reflections); + TypeHandlerLibrary serializationLibrary = new TypeHandlerLibraryImpl(reflections); EntitySystemLibrary entitySystemLibrary = new EntitySystemLibrary(context, serializationLibrary); PojoEntityManager entityManager = new PojoEntityManager(); diff --git a/engine/build.gradle b/engine/build.gradle index 8267ad1a6e6..03959bd10d5 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -151,6 +151,8 @@ dependencies { // TODO: Consider moving this back to the PC Facade instead of having the engine rely on it? implementation group: 'org.terasology.crashreporter', name: 'cr-terasology', version: '4.1.0' + + api(project(":subsystems:TypeHandlerLibrary")) } task cacheReflections { @@ -179,11 +181,13 @@ jar { from(tasks.getByName("cacheReflections").outputs) - manifest { - def manifestClasspath = "$subDirLibs/" + configurations."${sourceSets.main.runtimeClasspathConfigurationName}".collect { - it.getName() - }.join(" $subDirLibs/") - attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology-" + project.name, "Implementation-Version": env.BUILD_NUMBER + ", " + convertGitBranch(env.GIT_BRANCH) + ", " + env.BUILD_ID + ", " + displayVersion) + doFirst { + manifest { + def manifestClasspath = "$subDirLibs/" + configurations."${sourceSets.main.runtimeClasspathConfigurationName}".collect { + it.getName() + }.join(" $subDirLibs/") + attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology-" + project.name, "Implementation-Version": env.BUILD_NUMBER + ", " + convertGitBranch(env.GIT_BRANCH) + ", " + env.BUILD_ID + ", " + displayVersion) + } } } diff --git a/engine/src/main/java/org/terasology/engine/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/TerasologyEngine.java index 09e298ff2b7..88cd04dd115 100644 --- a/engine/src/main/java/org/terasology/engine/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/TerasologyEngine.java @@ -50,6 +50,7 @@ import org.terasology.nui.skin.UISkin; import org.terasology.nui.skin.UISkinData; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.recording.CharacterStateEventPositionMap; import org.terasology.recording.DirectionAndOriginPosRecorderList; import org.terasology.recording.RecordAndReplayCurrentStatus; @@ -326,7 +327,7 @@ private void initManagers() { CopyStrategyLibrary copyStrategyLibrary = new CopyStrategyLibrary(reflectFactory); rootContext.put(CopyStrategyLibrary.class, copyStrategyLibrary); - rootContext.put(TypeHandlerLibrary.class, TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry)); + rootContext.put(TypeHandlerLibrary.class, TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry)); changeStatus(TerasologyEngineStatus.INITIALIZING_ASSET_TYPES); assetTypeManager = new ModuleAwareAssetTypeManager(); diff --git a/engine/src/main/java/org/terasology/engine/bootstrap/EntitySystemSetupUtil.java b/engine/src/main/java/org/terasology/engine/bootstrap/EntitySystemSetupUtil.java index bc8ec706bff..f3290ba8ddd 100644 --- a/engine/src/main/java/org/terasology/engine/bootstrap/EntitySystemSetupUtil.java +++ b/engine/src/main/java/org/terasology/engine/bootstrap/EntitySystemSetupUtil.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.bootstrap; @@ -43,6 +30,7 @@ import org.terasology.network.NetworkSystem; import org.terasology.nui.properties.OneOfProviderFactory; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.extensionTypes.EntityRefTypeHandler; import org.terasology.recording.CharacterStateEventPositionMap; import org.terasology.recording.DirectionAndOriginPosRecorderList; @@ -79,7 +67,7 @@ public static void addReflectionBasedLibraries(Context context) { ModuleManager moduleManager = context.get(ModuleManager.class); TypeRegistry typeRegistry = context.get(TypeRegistry.class); - TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry); + TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); context.put(TypeHandlerLibrary.class, typeHandlerLibrary); EntitySystemLibrary library = new EntitySystemLibrary(context, typeHandlerLibrary); diff --git a/engine/src/main/java/org/terasology/engine/bootstrap/EnvironmentSwitchHandler.java b/engine/src/main/java/org/terasology/engine/bootstrap/EnvironmentSwitchHandler.java index 7d91bde0409..e8d014df33e 100644 --- a/engine/src/main/java/org/terasology/engine/bootstrap/EnvironmentSwitchHandler.java +++ b/engine/src/main/java/org/terasology/engine/bootstrap/EnvironmentSwitchHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.bootstrap; import org.slf4j.Logger; @@ -21,7 +8,6 @@ import org.terasology.assets.module.ModuleAwareAssetTypeManager; import org.terasology.config.flexible.AutoConfigManager; import org.terasology.context.Context; -import org.terasology.engine.SimpleUri; import org.terasology.engine.module.ModuleManager; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.metadata.ComponentLibrary; @@ -38,6 +24,7 @@ import org.terasology.persistence.typeHandling.TypeHandler; import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.extensionTypes.CollisionGroupTypeHandler; import org.terasology.physics.CollisionGroup; import org.terasology.physics.CollisionGroupManager; @@ -93,7 +80,7 @@ public void handleSwitchToGameEnvironment(Context context) { // TypeHandlerLibrary typeHandlerLibrary = context.get(TypeHandlerLibrary.class); // typeHandlerLibrary.addTypeHandler(CollisionGroup.class, new CollisionGroupTypeHandler(context.get(CollisionGroupManager.class))); - TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager,typeRegistry); + TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); typeHandlerLibrary.addTypeHandler(CollisionGroup.class, new CollisionGroupTypeHandler(context.get(CollisionGroupManager.class))); context.put(TypeHandlerLibrary.class, typeHandlerLibrary); diff --git a/engine/src/main/java/org/terasology/network/internal/NetworkSystemImpl.java b/engine/src/main/java/org/terasology/network/internal/NetworkSystemImpl.java index d614cd7c141..2efd01daabf 100644 --- a/engine/src/main/java/org/terasology/network/internal/NetworkSystemImpl.java +++ b/engine/src/main/java/org/terasology/network/internal/NetworkSystemImpl.java @@ -574,7 +574,7 @@ public void connectToEntitySystem(EngineEntityManager newEntityManager, EventLib context.get(ComponentSystemManager.class).register(new NetworkEntitySystem(this), "engine:networkEntitySystem"); - TypeHandlerLibrary typeHandlerLibrary = new TypeHandlerLibrary(entityManager.getTypeSerializerLibrary()); + TypeHandlerLibrary typeHandlerLibrary = entityManager.getTypeSerializerLibrary().copy(); typeHandlerLibrary.addTypeHandler(EntityRef.class, new NetEntityRefTypeHandler(this, blockEntityRegistry)); // TODO: Add network override types here (that use id lookup tables) diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java b/engine/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java deleted file mode 100644 index cd2387c034d..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling; - -/** - * This exception is thrown when deserializing a type fails - */ -public class DeserializationException extends RuntimeException { - - private static final long serialVersionUID = -6211402729551315020L; - - public DeserializationException() { - } - - public DeserializationException(String message) { - super(message); - } - - public DeserializationException(String message, Throwable cause) { - super(message, cause); - } - - public DeserializationException(Throwable cause) { - super(cause); - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java b/engine/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java deleted file mode 100644 index dff9c79c7fb..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling; - -/** - * This exception is thrown when deserializing a type fails - */ -public class SerializationException extends RuntimeException { - - private static final long serialVersionUID = -9046087332035665508L; - - public SerializationException() { - } - - public SerializationException(String message) { - super(message); - } - - public SerializationException(String message, Throwable cause) { - super(message, cause); - } - - public SerializationException(Throwable cause) { - super(cause); - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java deleted file mode 100644 index 8ae79f5a2d2..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.persistence.typeHandling; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.joml.AABBf; -import org.joml.AABBi; -import org.joml.Quaternionf; -import org.joml.Quaternionfc; -import org.joml.Vector2fc; -import org.joml.Vector2ic; -import org.joml.Vector3fc; -import org.joml.Vector3ic; -import org.joml.Vector4fc; -import org.joml.Vector4ic; -import org.reflections.Reflections; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.engine.module.ModuleManager; -import org.terasology.entitySystem.prefab.Prefab; -import org.terasology.math.IntegerRange; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector2i; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; -import org.terasology.math.geom.Vector4f; -import org.terasology.naming.Name; -import org.terasology.nui.Color; -import org.terasology.nui.Colorc; -import org.terasology.nui.UITextureRegion; -import org.terasology.persistence.typeHandling.coreTypes.BooleanTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.ByteArrayTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.ByteTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.CharacterTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.DoubleTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.FloatTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.IntTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.LongTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.NumberTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.StringTypeHandler; -import org.terasology.persistence.typeHandling.coreTypes.factories.ArrayTypeHandlerFactory; -import org.terasology.persistence.typeHandling.coreTypes.factories.CollectionTypeHandlerFactory; -import org.terasology.persistence.typeHandling.coreTypes.factories.EnumTypeHandlerFactory; -import org.terasology.persistence.typeHandling.coreTypes.factories.ObjectFieldMapTypeHandlerFactory; -import org.terasology.persistence.typeHandling.coreTypes.factories.StringMapTypeHandlerFactory; -import org.terasology.persistence.typeHandling.extensionTypes.ColorTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.ColorcTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.NameTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.PrefabTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.TextureRegionTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.UITextureRegionTypeHandler; -import org.terasology.persistence.typeHandling.extensionTypes.factories.AssetTypeHandlerFactory; -import org.terasology.persistence.typeHandling.extensionTypes.factories.ComponentClassTypeHandlerFactory; -import org.terasology.persistence.typeHandling.extensionTypes.factories.TextureRegionAssetTypeHandlerFactory; -import org.terasology.persistence.typeHandling.mathTypes.AABBfTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.AABBiTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.BlockRegionTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.IntegerRangeHandler; -import org.terasology.persistence.typeHandling.mathTypes.QuaternionfTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.QuaternionfcTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector2fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector2fcTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector2iTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector2icTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector3fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector3fcTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector3iTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector3icTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector4fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector4fcTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector4iTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.Vector4icTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.factories.Rect2fTypeHandlerFactory; -import org.terasology.persistence.typeHandling.mathTypes.factories.Rect2iTypeHandlerFactory; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyQuat4fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector2fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector2iTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3iTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector4fTypeHandler; -import org.terasology.persistence.typeHandling.reflection.ModuleEnvironmentSandbox; -import org.terasology.persistence.typeHandling.reflection.ReflectionsSandbox; -import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; -import org.terasology.reflection.TypeInfo; -import org.terasology.reflection.TypeRegistry; -import org.terasology.reflection.metadata.ClassMetadata; -import org.terasology.reflection.metadata.FieldMetadata; -import org.terasology.reflection.reflect.ConstructorLibrary; -import org.terasology.rendering.assets.texture.TextureRegion; -import org.terasology.world.block.BlockRegion; - - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * A library of type handlers. This is used for the construction of class metadata. - * This library should be initialised by adding a number of base type handlers, describing how to serialize each supported type. - * It will then produce serializers for classes (through their ClassMetadata) on request. - */ -public class TypeHandlerLibrary { - private static final Logger logger = LoggerFactory.getLogger(TypeHandlerLibrary.class); - - private SerializationSandbox sandbox; - - private List typeHandlerFactories = Lists.newArrayList(); - - private Map, TypeHandler> typeHandlerCache = Maps.newHashMap(); - - /** - * In certain object graphs, creating a {@link TypeHandler} for a type may recursively - * require an {@link TypeHandler} for the same type. Without intervention, the recursive - * lookup would stack overflow. Thus, for type handlers in the process of being created, - * we return a delegate to the {@link TypeHandler} via {@link FutureTypeHandler} which is - * wired after the {@link TypeHandler} has been created. - */ - private final ThreadLocal, FutureTypeHandler>> futureTypeHandlers = new ThreadLocal<>(); - - private Map> instanceCreators = Maps.newHashMap(); - private ConstructorLibrary constructorLibrary; - - private Map, Serializer> serializerMap = Maps.newHashMap(); - - private TypeHandlerLibrary(SerializationSandbox sandbox) { - this.sandbox = sandbox; - - constructorLibrary = new ConstructorLibrary(instanceCreators); - - addTypeHandlerFactory(new ObjectFieldMapTypeHandlerFactory(constructorLibrary)); - - addTypeHandler(Boolean.class, new BooleanTypeHandler()); - addTypeHandler(Boolean.TYPE, new BooleanTypeHandler()); - addTypeHandler(Byte.class, new ByteTypeHandler()); - addTypeHandler(Byte.TYPE, new ByteTypeHandler()); - addTypeHandler(Character.class, new CharacterTypeHandler()); - addTypeHandler(Character.TYPE, new CharacterTypeHandler()); - addTypeHandler(Double.class, new DoubleTypeHandler()); - addTypeHandler(Double.TYPE, new DoubleTypeHandler()); - addTypeHandler(Float.class, new FloatTypeHandler()); - addTypeHandler(Float.TYPE, new FloatTypeHandler()); - addTypeHandler(Integer.class, new IntTypeHandler()); - addTypeHandler(Integer.TYPE, new IntTypeHandler()); - addTypeHandler(Long.class, new LongTypeHandler()); - addTypeHandler(Long.TYPE, new LongTypeHandler()); - addTypeHandler(String.class, new StringTypeHandler()); - addTypeHandler(Number.class, new NumberTypeHandler()); - - addTypeHandlerFactory(new ArrayTypeHandlerFactory()); - addTypeHandler(byte[].class, new ByteArrayTypeHandler()); - - addTypeHandlerFactory(new EnumTypeHandlerFactory()); - addTypeHandlerFactory(new CollectionTypeHandlerFactory(constructorLibrary)); - addTypeHandlerFactory(new StringMapTypeHandlerFactory()); - - addTypeHandlerFactory(new ComponentClassTypeHandlerFactory()); - } - - /** - * - */ - public TypeHandlerLibrary(Reflections reflections) { - this(new ReflectionsSandbox(reflections)); - } - - public TypeHandlerLibrary(ModuleManager moduleManager, TypeRegistry typeRegistry) { - this(new ModuleEnvironmentSandbox(moduleManager, typeRegistry)); - } - - /** - * Creates a copy of an existing serialization library. This copy is initialised with all type handlers that were added to the original, but does not retain any - * serializers or type handlers that were generated. This can be used to override specific types handlers from another type serializer. - * - * @param original The original type serialization library to copy. - */ - public TypeHandlerLibrary(TypeHandlerLibrary original) { - this.typeHandlerFactories.addAll(original.typeHandlerFactories); - this.instanceCreators.putAll(original.instanceCreators); - this.sandbox = original.sandbox; - } - - public static TypeHandlerLibrary withReflections(Reflections reflections) { - TypeHandlerLibrary library = new TypeHandlerLibrary(reflections); - - populateWithDefaultHandlers(library); - - return library; - } - - public static TypeHandlerLibrary forModuleEnvironment(ModuleManager moduleManager, TypeRegistry typeRegistry) { - TypeHandlerLibrary library = new TypeHandlerLibrary(moduleManager, typeRegistry); - - populateWithDefaultHandlers(library); - - return library; - } - - private static void populateWithDefaultHandlers(TypeHandlerLibrary serializationLibrary) { - // LEGACY - serializationLibrary.addTypeHandler(Vector4f.class, new LegacyVector4fTypeHandler()); - serializationLibrary.addTypeHandler(Vector3f.class, new LegacyVector3fTypeHandler()); - serializationLibrary.addTypeHandler(Vector2f.class, new LegacyVector2fTypeHandler()); - serializationLibrary.addTypeHandler(Vector3i.class, new LegacyVector3iTypeHandler()); - serializationLibrary.addTypeHandler(Vector2i.class, new LegacyVector2iTypeHandler()); - serializationLibrary.addTypeHandler(Quat4f.class, new LegacyQuat4fTypeHandler()); - - // Current Supported - serializationLibrary.addTypeHandlerFactory(new AssetTypeHandlerFactory()); - - serializationLibrary.addTypeHandler(Name.class, new NameTypeHandler()); - serializationLibrary.addTypeHandler(TextureRegion.class, new TextureRegionTypeHandler()); - serializationLibrary.addTypeHandler(UITextureRegion.class, new UITextureRegionTypeHandler()); - - serializationLibrary.addTypeHandlerFactory(new TextureRegionAssetTypeHandlerFactory()); - - serializationLibrary.addTypeHandler(Color.class, new ColorTypeHandler()); - serializationLibrary.addTypeHandler(Colorc.class, new ColorcTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector4f.class, new Vector4fTypeHandler()); - serializationLibrary.addTypeHandler(Vector4fc.class, new Vector4fcTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector3f.class, new Vector3fTypeHandler()); - serializationLibrary.addTypeHandler(Vector3fc.class, new Vector3fcTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector2f.class, new Vector2fTypeHandler()); - serializationLibrary.addTypeHandler(Vector2fc.class, new Vector2fcTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector3i.class, new Vector3iTypeHandler()); - serializationLibrary.addTypeHandler(Vector3ic.class, new Vector3icTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector2i.class, new Vector2iTypeHandler()); - serializationLibrary.addTypeHandler(Vector2ic.class, new Vector2icTypeHandler()); - - serializationLibrary.addTypeHandler(org.joml.Vector4i.class, new Vector4iTypeHandler()); - serializationLibrary.addTypeHandler(Vector4ic.class, new Vector4icTypeHandler()); - - serializationLibrary.addTypeHandler(AABBi.class, new AABBiTypeHandler()); - serializationLibrary.addTypeHandler(AABBf.class, new AABBfTypeHandler()); - serializationLibrary.addTypeHandler(BlockRegion.class, new BlockRegionTypeHandler()); - - serializationLibrary.addTypeHandler(Quaternionf.class, new QuaternionfTypeHandler()); - serializationLibrary.addTypeHandler(Quaternionfc.class, new QuaternionfcTypeHandler()); - - serializationLibrary.addTypeHandlerFactory(new Rect2iTypeHandlerFactory()); - serializationLibrary.addTypeHandlerFactory(new Rect2fTypeHandlerFactory()); - serializationLibrary.addTypeHandler(Prefab.class, new PrefabTypeHandler()); - serializationLibrary.addTypeHandler(IntegerRange.class, new IntegerRangeHandler()); - } - - /** - * Obtains a serializer for the given type - * - * @param type The ClassMetadata for the type of interest - * @return A serializer for serializing/deserializing the type - */ - public Serializer getSerializerFor(ClassMetadata type) { - Serializer serializer = serializerMap.get(type); - if (serializer == null) { - Map, TypeHandler> fieldHandlerMap = getFieldHandlerMap(type); - serializer = new Serializer(type, fieldHandlerMap); - serializerMap.put(type, serializer); - } - return serializer; - } - - /** - * Adds a new {@link TypeHandlerFactory} to the {@link TypeHandlerLibrary}. Factories - * added later are given a higher priority during {@link TypeHandler} generation. - */ - public void addTypeHandlerFactory(TypeHandlerFactory typeHandlerFactory) { - typeHandlerFactories.add(typeHandlerFactory); - } - - /** - * Adds a {@link TypeHandler} for the specified type to this {@link TypeHandlerLibrary} by - * adding to the library a new {@link TypeHandlerFactory} that returns the {@link TypeHandler} - * whenever the {@link TypeHandler} for the specified type is requested. - *

- * If the specified {@link SerializationSandbox} does not allow the addition of the given - * {@link TypeHandler} for the given type, the {@link TypeHandler} is not added to the - * library and false is returned. - * - * @param typeClass The {@link Class} of the type handled by the {@link TypeHandler}. - * @param typeHandler The {@link TypeHandler} to add to the library. - * @param The type handled by the {@link TypeHandler}. - * @return True if the {@link TypeHandler} was successfully added, false otherwise. - */ - public boolean addTypeHandler(Class typeClass, TypeHandler typeHandler) { - return addTypeHandler(TypeInfo.of(typeClass), typeHandler); - } - - /** - * Adds a {@link TypeHandler} for the specified type to this {@link TypeHandlerLibrary} by - * adding to the library a new {@link TypeHandlerFactory} that returns the {@link TypeHandler} - * whenever the {@link TypeHandler} for the specified type is requested. - *

- * If the specified {@link SerializationSandbox} does not allow the addition of the given - * {@link TypeHandler} for the given type, the {@link TypeHandler} is not added to the - * library and false is returned. - * - * @param The type handled by the {@link TypeHandler}. - * @param type The {@link TypeInfo} of the type handled by the {@link TypeHandler}. - * @param typeHandler The {@link TypeHandler} to add to the library. - * @return True if the {@link TypeHandler} was successfully added, false otherwise. - */ - public boolean addTypeHandler(TypeInfo type, TypeHandler typeHandler) { - if (!sandbox.isValidTypeHandlerDeclaration(type, typeHandler)) { - return false; - } - - addTypeHandlerFactory(new SpecificTypeHandlerFactory(type) { - @Override - protected TypeHandler createHandler(TypeHandlerContext context) { - return typeHandler; - } - }); - - return true; - } - - /** - * Adds an {@link InstanceCreator} to the {@link TypeHandlerLibrary} for the specified type. - */ - public void addInstanceCreator(Class typeClass, InstanceCreator instanceCreator) { - addInstanceCreator(TypeInfo.of(typeClass), instanceCreator); - } - - /** - * Adds an {@link InstanceCreator} to the {@link TypeHandlerLibrary} for the specified type. - */ - public void addInstanceCreator(TypeInfo typeInfo, InstanceCreator instanceCreator) { - instanceCreators.put(typeInfo.getType(), instanceCreator); - } - - /** - * Retrieves the {@link TypeHandler} for the specified type, if available. - *

- * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested - * to generate a {@link TypeHandler} for the given type. Most recently added factories are - * requested first, hence a {@link TypeHandlerFactory} can override one that was added - * before it. - * - * @param type The {@link Type} describing the type for which to - * retrieve the {@link TypeHandler}. - * @return The {@link TypeHandler} for the specified type, if available. - */ - @SuppressWarnings({"unchecked"}) - public Optional> getTypeHandler(Type type) { - TypeInfo typeInfo = TypeInfo.of(type); - return (Optional>) getTypeHandler(typeInfo); - } - - /** - * Retrieves the {@link TypeHandler} for the specified type, if available. - *

- * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested - * to generate a {@link TypeHandler} for the given type. Most recently added factories are - * requested first, hence a {@link TypeHandlerFactory} can override one that was added - * before it. - * - * @param typeClass The {@link Class} of the type for which to - * retrieve the {@link TypeHandler}. - * @param The type for which to retrieve the {@link TypeHandler}. - * @return The {@link TypeHandler} for the specified type, if available. - */ - public Optional> getTypeHandler(Class typeClass) { - return getTypeHandler(TypeInfo.of(typeClass)); - } - - /** - * Retrieves the {@link TypeHandler} for the specified type, if available. - *

- * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested - * to generate a {@link TypeHandler} for the given type. Most recently added factories are - * requested first, hence a {@link TypeHandlerFactory} can override one that was added - * before it. - * - * @param type The {@link TypeInfo} describing the type for which to - * retrieve the {@link TypeHandler}. - * @param The type for which to retrieve the {@link TypeHandler}. - * @return The {@link TypeHandler} for the specified type, if available. - */ - @SuppressWarnings("unchecked") - public Optional> getTypeHandler(TypeInfo type) { - TypeHandlerContext context = new TypeHandlerContext(this, sandbox); - - if (typeHandlerCache.containsKey(type)) { - return Optional.of((TypeHandler) typeHandlerCache.get(type)); - } - - Map, FutureTypeHandler> futures = futureTypeHandlers.get(); - boolean cleanupFutureTypeHandlers = false; - - if (futures == null) { - cleanupFutureTypeHandlers = true; - futures = new HashMap<>(); - futureTypeHandlers.set(futures); - } - - FutureTypeHandler future = (FutureTypeHandler) futures.get(type); - - if (future != null) { - return Optional.of(future); - } - - try { - future = new FutureTypeHandler<>(); - futures.put(type, future); - - // TODO: Explore reversing typeHandlerFactories itself before building object - for (int i = typeHandlerFactories.size() - 1; i >= 0; i--) { - TypeHandlerFactory typeHandlerFactory = typeHandlerFactories.get(i); - Optional> typeHandler = typeHandlerFactory.create(type, context); - - if (typeHandler.isPresent()) { - TypeHandler handler = typeHandler.get(); - - if (!sandbox.isValidTypeHandlerDeclaration(type, handler)) { - continue; - } - - typeHandlerCache.put(type, handler); - future.typeHandler = handler; - - return Optional.of(handler); - } - } - - return Optional.empty(); - } finally { - futures.remove(type); - - if (cleanupFutureTypeHandlers) { - futureTypeHandlers.remove(); - } - } - } - - /** - * Returns a {@link TypeHandler} that can handle all types deriving from {@link T}. - * - * @param typeInfo The {@link TypeInfo} describing the base type for which to return a - * {@link TypeHandler}. - * @param The base type for which to return a {@link TypeHandler}. - */ - public TypeHandler getBaseTypeHandler(TypeInfo typeInfo) { - TypeHandler delegateHandler = getTypeHandler(typeInfo).orElse(null); - - TypeHandlerContext context = new TypeHandlerContext(this, sandbox); - return new RuntimeDelegatingTypeHandler<>(delegateHandler, typeInfo, context); - } - - private Map, TypeHandler> getFieldHandlerMap(ClassMetadata type) { - Map, TypeHandler> handlerMap = Maps.newHashMap(); - for (FieldMetadata field : type.getFields()) { - Optional> handler = getTypeHandler(field.getField().getGenericType()); - - if (handler.isPresent()) { - handlerMap.put(field, handler.get()); - } else { - logger.error("Unsupported field: '{}.{}'", type.getUri(), field.getName()); - } - } - return handlerMap; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java new file mode 100644 index 00000000000..4ff9d829033 --- /dev/null +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java @@ -0,0 +1,162 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling; + +import org.joml.AABBf; +import org.joml.AABBi; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector2fc; +import org.joml.Vector2ic; +import org.joml.Vector3fc; +import org.joml.Vector3ic; +import org.joml.Vector4fc; +import org.joml.Vector4ic; +import org.reflections.Reflections; +import org.terasology.engine.module.ModuleManager; +import org.terasology.entitySystem.prefab.Prefab; +import org.terasology.math.IntegerRange; +import org.terasology.math.geom.Quat4f; +import org.terasology.math.geom.Vector2f; +import org.terasology.math.geom.Vector2i; +import org.terasology.math.geom.Vector3f; +import org.terasology.math.geom.Vector3i; +import org.terasology.math.geom.Vector4f; +import org.terasology.naming.Name; +import org.terasology.nui.Color; +import org.terasology.nui.Colorc; +import org.terasology.nui.UITextureRegion; +import org.terasology.persistence.typeHandling.extensionTypes.ColorTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.ColorcTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.NameTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.PrefabTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.TextureRegionTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.UITextureRegionTypeHandler; +import org.terasology.persistence.typeHandling.extensionTypes.factories.AssetTypeHandlerFactory; +import org.terasology.persistence.typeHandling.extensionTypes.factories.ComponentClassTypeHandlerFactory; +import org.terasology.persistence.typeHandling.extensionTypes.factories.TextureRegionAssetTypeHandlerFactory; +import org.terasology.persistence.typeHandling.mathTypes.AABBfTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.AABBiTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.BlockRegionTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.IntegerRangeHandler; +import org.terasology.persistence.typeHandling.mathTypes.QuaternionfTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.QuaternionfcTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector2fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector2fcTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector2iTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector2icTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector3fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector3fcTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector3iTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector3icTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector4fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector4fcTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector4iTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.Vector4icTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.factories.Rect2fTypeHandlerFactory; +import org.terasology.persistence.typeHandling.mathTypes.factories.Rect2iTypeHandlerFactory; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyQuat4fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector2fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector2iTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3fTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3iTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector4fTypeHandler; +import org.terasology.persistence.typeHandling.reflection.ModuleEnvironmentSandbox; +import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; +import org.terasology.reflection.TypeRegistry; +import org.terasology.rendering.assets.texture.TextureRegion; +import org.terasology.world.block.BlockRegion; + +/** + * A library of type handlers. This is used for the construction of class metadata. This library should be initialised + * by adding a number of base type handlers, describing how to serialize each supported type. It will then produce + * serializers for classes (through their ClassMetadata) on request. + */ +public class TypeHandlerLibraryImpl extends TypeHandlerLibrary { + + + public TypeHandlerLibraryImpl(Reflections reflections) { + super(reflections); + addTypeHandlerFactory(new ComponentClassTypeHandlerFactory()); + } + + protected TypeHandlerLibraryImpl(SerializationSandbox sandbox) { + super(sandbox); + addTypeHandlerFactory(new ComponentClassTypeHandlerFactory()); + } + + public TypeHandlerLibraryImpl(ModuleManager moduleManager, TypeRegistry typeRegistry) { + super(new ModuleEnvironmentSandbox(moduleManager, typeRegistry)); + } + + + public static TypeHandlerLibrary withReflections(Reflections reflections) { + TypeHandlerLibrary library = new TypeHandlerLibraryImpl(reflections); + + populateWithDefaultHandlers(library); + + return library; + } + + public static TypeHandlerLibrary forModuleEnvironment(ModuleManager moduleManager, TypeRegistry typeRegistry) { + TypeHandlerLibrary library = new TypeHandlerLibraryImpl(moduleManager, typeRegistry); + + populateWithDefaultHandlers(library); + + return library; + } + + private static void populateWithDefaultHandlers(TypeHandlerLibrary serializationLibrary) { + // LEGACY + serializationLibrary.addTypeHandler(Vector4f.class, new LegacyVector4fTypeHandler()); + serializationLibrary.addTypeHandler(Vector3f.class, new LegacyVector3fTypeHandler()); + serializationLibrary.addTypeHandler(Vector2f.class, new LegacyVector2fTypeHandler()); + serializationLibrary.addTypeHandler(Vector3i.class, new LegacyVector3iTypeHandler()); + serializationLibrary.addTypeHandler(Vector2i.class, new LegacyVector2iTypeHandler()); + serializationLibrary.addTypeHandler(Quat4f.class, new LegacyQuat4fTypeHandler()); + + // Current Supported + serializationLibrary.addTypeHandlerFactory(new AssetTypeHandlerFactory()); + + serializationLibrary.addTypeHandler(Name.class, new NameTypeHandler()); + serializationLibrary.addTypeHandler(TextureRegion.class, new TextureRegionTypeHandler()); + serializationLibrary.addTypeHandler(UITextureRegion.class, new UITextureRegionTypeHandler()); + + serializationLibrary.addTypeHandlerFactory(new TextureRegionAssetTypeHandlerFactory()); + + serializationLibrary.addTypeHandler(Color.class, new ColorTypeHandler()); + serializationLibrary.addTypeHandler(Colorc.class, new ColorcTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector4f.class, new Vector4fTypeHandler()); + serializationLibrary.addTypeHandler(Vector4fc.class, new Vector4fcTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector3f.class, new Vector3fTypeHandler()); + serializationLibrary.addTypeHandler(Vector3fc.class, new Vector3fcTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector2f.class, new Vector2fTypeHandler()); + serializationLibrary.addTypeHandler(Vector2fc.class, new Vector2fcTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector3i.class, new Vector3iTypeHandler()); + serializationLibrary.addTypeHandler(Vector3ic.class, new Vector3icTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector2i.class, new Vector2iTypeHandler()); + serializationLibrary.addTypeHandler(Vector2ic.class, new Vector2icTypeHandler()); + + serializationLibrary.addTypeHandler(org.joml.Vector4i.class, new Vector4iTypeHandler()); + serializationLibrary.addTypeHandler(Vector4ic.class, new Vector4icTypeHandler()); + + serializationLibrary.addTypeHandler(AABBi.class, new AABBiTypeHandler()); + serializationLibrary.addTypeHandler(AABBf.class, new AABBfTypeHandler()); + serializationLibrary.addTypeHandler(BlockRegion.class, new BlockRegionTypeHandler()); + + serializationLibrary.addTypeHandler(Quaternionf.class, new QuaternionfTypeHandler()); + serializationLibrary.addTypeHandler(Quaternionfc.class, new QuaternionfcTypeHandler()); + + serializationLibrary.addTypeHandlerFactory(new Rect2iTypeHandlerFactory()); + serializationLibrary.addTypeHandlerFactory(new Rect2fTypeHandlerFactory()); + serializationLibrary.addTypeHandler(Prefab.class, new PrefabTypeHandler()); + serializationLibrary.addTypeHandler(IntegerRange.class, new IntegerRangeHandler()); + } + +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java b/engine/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java deleted file mode 100644 index 71775885abc..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2019 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An annotation that indicates that the decorated field should be serialized with - * the provided name value as its field name. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.FIELD}) -public @interface SerializedName { - /** - * @return the desired name of the field when it is serialized or deserialized. - */ - String value(); -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java deleted file mode 100644 index d0e5bcb1fb3..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedBoolean extends AbstractPersistedData { - private boolean data; - - public PersistedBoolean(boolean data) { - this.data = data; - } - - @Override - public boolean getAsBoolean() { - return data; - } - - @Override - public boolean isBoolean() { - return true; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java deleted file mode 100644 index 8983759de03..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedDouble extends PersistedNumber { - private double data; - - public PersistedDouble(double data) { - this.data = data; - } - - @Override - public double getAsDouble() { - return data; - } - - @Override - public float getAsFloat() { - return (float) data; - } - - @Override - public int getAsInteger() { - return (int) data; - } - - @Override - public long getAsLong() { - return (long) data; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java deleted file mode 100644 index 24c01c277c6..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedFloat extends PersistedNumber { - - private float data; - - public PersistedFloat(float data) { - this.data = data; - } - - @Override - public double getAsDouble() { - return data; - } - - @Override - public float getAsFloat() { - return data; - } - - @Override - public int getAsInteger() { - return (int) data; - } - - @Override - public long getAsLong() { - return (long) data; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java deleted file mode 100644 index e7f914d1983..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedInteger extends PersistedNumber { - private int data; - - public PersistedInteger(int data) { - this.data = data; - } - - @Override - public double getAsDouble() { - return data; - } - - @Override - public float getAsFloat() { - return data; - } - - @Override - public int getAsInteger() { - return data; - } - - @Override - public long getAsLong() { - return data; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java deleted file mode 100644 index 9a29516f7e5..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedLong extends PersistedNumber { - private long data; - - public PersistedLong(long data) { - this.data = data; - } - - @Override - public double getAsDouble() { - return data; - } - - @Override - public float getAsFloat() { - return data; - } - - @Override - public int getAsInteger() { - return (int) data; - } - - @Override - public long getAsLong() { - return data; - } -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java deleted file mode 100644 index 16044d8e0cd..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public abstract class PersistedNumber extends AbstractPersistedData { - - @Override - public boolean isNumber() { - return true; - } - - @Override - public abstract double getAsDouble(); - - @Override - public abstract float getAsFloat(); - - @Override - public abstract int getAsInteger(); - - @Override - public abstract long getAsLong(); -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java b/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java deleted file mode 100644 index e90af5d157b..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.persistence.typeHandling.inMemory; - -/** - */ -public class PersistedString extends AbstractPersistedData { - - private String data; - - public PersistedString(String data) { - this.data = data; - } - - @Override - public String getAsString() { - return data; - } - - @Override - public boolean isString() { - return true; - } - -} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/package-info.java b/engine/src/main/java/org/terasology/persistence/typeHandling/package-info.java deleted file mode 100644 index 8590bd6b36b..00000000000 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * This package contains the interfaces and abstract classes for use when defining type handlers. - * Type handlers provide the algorithms for serializing and deserializing types - this uses an implementation agnostic set of interfaces - * so TypeHandlers can be used for different serialization techniques (Json, Protobuf, etc). - */ -@API package org.terasology.persistence.typeHandling; - -import org.terasology.module.sandbox.API; diff --git a/engine/src/main/java/org/terasology/recording/RecordedEventSerializer.java b/engine/src/main/java/org/terasology/recording/RecordedEventSerializer.java index 92fe46da2ca..d9d639aca09 100644 --- a/engine/src/main/java/org/terasology/recording/RecordedEventSerializer.java +++ b/engine/src/main/java/org/terasology/recording/RecordedEventSerializer.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.recording; import org.slf4j.Logger; @@ -24,6 +11,7 @@ import org.terasology.persistence.serializers.GsonSerializer; import org.terasology.persistence.typeHandling.SerializationException; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.extensionTypes.EntityRefTypeHandler; import org.terasology.reflection.TypeInfo; import org.terasology.reflection.TypeRegistry; @@ -43,7 +31,7 @@ class RecordedEventSerializer { private GsonSerializer gsonSerializer; public RecordedEventSerializer(EntityManager entityManager, ModuleManager moduleManager, TypeRegistry typeRegistry) { - TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibrary.forModuleEnvironment(moduleManager, typeRegistry); + TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); typeHandlerLibrary.addTypeHandler(EntityRef.class, new EntityRefTypeHandler((EngineEntityManager) entityManager)); gsonSerializer = new GsonSerializer(typeHandlerLibrary); diff --git a/engine/src/main/java/org/terasology/rendering/nui/asset/UIFormat.java b/engine/src/main/java/org/terasology/rendering/nui/asset/UIFormat.java index 30ca65fe887..f3d64974356 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/asset/UIFormat.java +++ b/engine/src/main/java/org/terasology/rendering/nui/asset/UIFormat.java @@ -1,18 +1,5 @@ -/* - * Copyright 2016 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.nui.asset; import com.google.common.base.Charsets; @@ -34,7 +21,12 @@ import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; import org.terasology.i18n.TranslationSystem; +import org.terasology.nui.LayoutHint; +import org.terasology.nui.UILayout; +import org.terasology.nui.UIWidget; import org.terasology.nui.asset.UIData; +import org.terasology.nui.skin.UISkin; +import org.terasology.nui.widgets.UILabel; import org.terasology.persistence.ModuleContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.persistence.typeHandling.extensionTypes.AssetTypeHandler; @@ -43,12 +35,7 @@ import org.terasology.reflection.metadata.FieldMetadata; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.nui.CoreScreenLayer; -import org.terasology.nui.LayoutHint; import org.terasology.rendering.nui.NUIManager; -import org.terasology.nui.UILayout; -import org.terasology.nui.UIWidget; -import org.terasology.nui.skin.UISkin; -import org.terasology.nui.widgets.UILabel; import org.terasology.utilities.ReflectionUtil; import org.terasology.utilities.gson.CaseInsensitiveEnumTypeAdapterFactory; @@ -98,7 +85,7 @@ public UIData load(JsonElement element) throws IOException { public UIData load(JsonElement element, Locale otherLocale) throws IOException { NUIManager nuiManager = CoreRegistry.get(NUIManager.class); TranslationSystem translationSystem = CoreRegistry.get(TranslationSystem.class); - TypeHandlerLibrary library = new TypeHandlerLibrary(CoreRegistry.get(TypeHandlerLibrary.class)); + TypeHandlerLibrary library = CoreRegistry.get(TypeHandlerLibrary.class).copy(); library.addTypeHandler(UISkin.class, new AssetTypeHandler<>(UISkin.class)); // TODO: Rewrite to use TypeHandlerLibrary diff --git a/subsystems/TypeHandlerLibrary/README.MD b/subsystems/TypeHandlerLibrary/README.MD new file mode 100644 index 00000000000..c190dd6d5d8 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/README.MD @@ -0,0 +1,72 @@ +# TypeHandlerLibrary + +>It is really not subsystem. but used by them + +A library of type handlers. This is used for the construction of class metadata. This library should be initialised +by adding a number of base type handlers, describing how to serialize each supported type. It will then produce +serializers for classes (through their ClassMetadata) on request. + +Type handlers provide the algorithms for serializing and deserializing types - this uses an implementation agnostic set of interfaces +so TypeHandlers can be used for different serialization techniques (Json, Protobuf, etc). + +#### Structure + +[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVEQgXG4gICAgVHlwZUhhbmRsZXJMaWJyYXJ5XG4gICAgVHlwZUhhbmRsZXJGYWN0b3J5XG4gICAgVHlwZUhhbmRsZXJcbiAgICBQZXJzaXN0ZW50RGF0YVxuICAgIFBlcnNpc3RlbnREYXRhU2VyaWFsaXplclxuICAgIFxuICAgIFR5cGVIYW5kbGVyTGlicmFyeSAtLS0-IHxwcm92aWRlc3wgVHlwZUhhbmRsZXJGYWN0b3J5XG4gICAgVHlwZUhhbmRsZXJGYWN0b3J5IC0tLT4gfHByb3ZpZGVzfCBUeXBlSGFuZGxlclxuICAgIFR5cGVIYW5kbGVyICYgVHlwZUhhbmRsZXJGYWN0b3J5IC0tLT4gfHJlZ2lzdGVyfCBUeXBlSGFuZGxlckxpYnJhcnlcbiAgICBcbiAgICBUeXBlSGFuZGxlciAtLS0-IHx1c2VzIGZvciBzZXJpYWxpemF0aW9ufCBQZXJzaXN0ZW50RGF0YVNlcmlhbGl6ZXJcbiAgICBUeXBlSGFuZGxlciAtLS0-IHxyZXN1bHQgb2Ygc2VyaWFsaXphdGlvbiB8IFBlcnNpc3RlbnREYXRhXG4gICAgVHlwZUhhbmRsZXIgLS0tPiB8c291cmNlIG9mIGRlc2VyaWFsaXphdGlvbiB8IFBlcnNpc3RlbnREYXRhXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCIsInRoZW1lVmFyaWFibGVzIjp7ImJhY2tncm91bmQiOiJ3aGl0ZSIsInByaW1hcnlDb2xvciI6IiNFQ0VDRkYiLCJzZWNvbmRhcnlDb2xvciI6IiNmZmZmZGUiLCJ0ZXJ0aWFyeUNvbG9yIjoiaHNsKDgwLCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJwcmltYXJ5Qm9yZGVyQ29sb3IiOiJoc2woMjQwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInNlY29uZGFyeUJvcmRlckNvbG9yIjoiaHNsKDYwLCA2MCUsIDgzLjUyOTQxMTc2NDclKSIsInRlcnRpYXJ5Qm9yZGVyQ29sb3IiOiJoc2woODAsIDYwJSwgODYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeVRleHRDb2xvciI6IiMxMzEzMDAiLCJzZWNvbmRhcnlUZXh0Q29sb3IiOiIjMDAwMDIxIiwidGVydGlhcnlUZXh0Q29sb3IiOiJyZ2IoOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEsIDkuNTAwMDAwMDAwMSkiLCJsaW5lQ29sb3IiOiIjMzMzMzMzIiwidGV4dENvbG9yIjoiIzMzMyIsIm1haW5Ca2ciOiIjRUNFQ0ZGIiwic2Vjb25kQmtnIjoiI2ZmZmZkZSIsImJvcmRlcjEiOiIjOTM3MERCIiwiYm9yZGVyMiI6IiNhYWFhMzMiLCJhcnJvd2hlYWRDb2xvciI6IiMzMzMzMzMiLCJmb250RmFtaWx5IjoiXCJ0cmVidWNoZXQgbXNcIiwgdmVyZGFuYSwgYXJpYWwiLCJmb250U2l6ZSI6IjE2cHgiLCJsYWJlbEJhY2tncm91bmQiOiIjZThlOGU4Iiwibm9kZUJrZyI6IiNFQ0VDRkYiLCJub2RlQm9yZGVyIjoiIzkzNzBEQiIsImNsdXN0ZXJCa2ciOiIjZmZmZmRlIiwiY2x1c3RlckJvcmRlciI6IiNhYWFhMzMiLCJkZWZhdWx0TGlua0NvbG9yIjoiIzMzMzMzMyIsInRpdGxlQ29sb3IiOiIjMzMzIiwiZWRnZUxhYmVsQmFja2dyb3VuZCI6IiNlOGU4ZTgiLCJhY3RvckJvcmRlciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImFjdG9yQmtnIjoiI0VDRUNGRiIsImFjdG9yVGV4dENvbG9yIjoiYmxhY2siLCJhY3RvckxpbmVDb2xvciI6ImdyZXkiLCJzaWduYWxDb2xvciI6IiMzMzMiLCJzaWduYWxUZXh0Q29sb3IiOiIjMzMzIiwibGFiZWxCb3hCa2dDb2xvciI6IiNFQ0VDRkYiLCJsYWJlbEJveEJvcmRlckNvbG9yIjoiaHNsKDI1OS42MjYxNjgyMjQzLCA1OS43NzY1MzYzMTI4JSwgODcuOTAxOTYwNzg0MyUpIiwibGFiZWxUZXh0Q29sb3IiOiJibGFjayIsImxvb3BUZXh0Q29sb3IiOiJibGFjayIsIm5vdGVCb3JkZXJDb2xvciI6IiNhYWFhMzMiLCJub3RlQmtnQ29sb3IiOiIjZmZmNWFkIiwibm90ZVRleHRDb2xvciI6ImJsYWNrIiwiYWN0aXZhdGlvbkJvcmRlckNvbG9yIjoiIzY2NiIsImFjdGl2YXRpb25Ca2dDb2xvciI6IiNmNGY0ZjQiLCJzZXF1ZW5jZU51bWJlckNvbG9yIjoid2hpdGUiLCJzZWN0aW9uQmtnQ29sb3IiOiJyZ2JhKDEwMiwgMTAyLCAyNTUsIDAuNDkpIiwiYWx0U2VjdGlvbkJrZ0NvbG9yIjoid2hpdGUiLCJzZWN0aW9uQmtnQ29sb3IyIjoiI2ZmZjQwMCIsInRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJ0YXNrQmtnQ29sb3IiOiIjOGE5MGRkIiwidGFza1RleHRMaWdodENvbG9yIjoid2hpdGUiLCJ0YXNrVGV4dENvbG9yIjoid2hpdGUiLCJ0YXNrVGV4dERhcmtDb2xvciI6ImJsYWNrIiwidGFza1RleHRPdXRzaWRlQ29sb3IiOiJibGFjayIsInRhc2tUZXh0Q2xpY2thYmxlQ29sb3IiOiIjMDAzMTYzIiwiYWN0aXZlVGFza0JvcmRlckNvbG9yIjoiIzUzNGZiYyIsImFjdGl2ZVRhc2tCa2dDb2xvciI6IiNiZmM3ZmYiLCJncmlkQ29sb3IiOiJsaWdodGdyZXkiLCJkb25lVGFza0JrZ0NvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCb3JkZXJDb2xvciI6ImdyZXkiLCJjcml0Qm9yZGVyQ29sb3IiOiIjZmY4ODg4IiwiY3JpdEJrZ0NvbG9yIjoicmVkIiwidG9kYXlMaW5lQ29sb3IiOiJyZWQiLCJsYWJlbENvbG9yIjoiYmxhY2siLCJlcnJvckJrZ0NvbG9yIjoiIzU1MjIyMiIsImVycm9yVGV4dENvbG9yIjoiIzU1MjIyMiIsImNsYXNzVGV4dCI6IiMxMzEzMDAiLCJmaWxsVHlwZTAiOiIjRUNFQ0ZGIiwiZmlsbFR5cGUxIjoiI2ZmZmZkZSIsImZpbGxUeXBlMiI6ImhzbCgzMDQsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlMyI6ImhzbCgxMjQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNCI6ImhzbCgxNzYsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlNSI6ImhzbCgtNCwgMTAwJSwgOTMuNTI5NDExNzY0NyUpIiwiZmlsbFR5cGU2IjoiaHNsKDgsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlNyI6ImhzbCgxODgsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSJ9fSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVEQgXG4gICAgVHlwZUhhbmRsZXJMaWJyYXJ5XG4gICAgVHlwZUhhbmRsZXJGYWN0b3J5XG4gICAgVHlwZUhhbmRsZXJcbiAgICBQZXJzaXN0ZW50RGF0YVxuICAgIFBlcnNpc3RlbnREYXRhU2VyaWFsaXplclxuICAgIFxuICAgIFR5cGVIYW5kbGVyTGlicmFyeSAtLS0-IHxwcm92aWRlc3wgVHlwZUhhbmRsZXJGYWN0b3J5XG4gICAgVHlwZUhhbmRsZXJGYWN0b3J5IC0tLT4gfHByb3ZpZGVzfCBUeXBlSGFuZGxlclxuICAgIFR5cGVIYW5kbGVyICYgVHlwZUhhbmRsZXJGYWN0b3J5IC0tLT4gfHJlZ2lzdGVyfCBUeXBlSGFuZGxlckxpYnJhcnlcbiAgICBcbiAgICBUeXBlSGFuZGxlciAtLS0-IHx1c2VzIGZvciBzZXJpYWxpemF0aW9ufCBQZXJzaXN0ZW50RGF0YVNlcmlhbGl6ZXJcbiAgICBUeXBlSGFuZGxlciAtLS0-IHxyZXN1bHQgb2Ygc2VyaWFsaXphdGlvbiB8IFBlcnNpc3RlbnREYXRhXG4gICAgVHlwZUhhbmRsZXIgLS0tPiB8c291cmNlIG9mIGRlc2VyaWFsaXphdGlvbiB8IFBlcnNpc3RlbnREYXRhXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCIsInRoZW1lVmFyaWFibGVzIjp7ImJhY2tncm91bmQiOiJ3aGl0ZSIsInByaW1hcnlDb2xvciI6IiNFQ0VDRkYiLCJzZWNvbmRhcnlDb2xvciI6IiNmZmZmZGUiLCJ0ZXJ0aWFyeUNvbG9yIjoiaHNsKDgwLCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJwcmltYXJ5Qm9yZGVyQ29sb3IiOiJoc2woMjQwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInNlY29uZGFyeUJvcmRlckNvbG9yIjoiaHNsKDYwLCA2MCUsIDgzLjUyOTQxMTc2NDclKSIsInRlcnRpYXJ5Qm9yZGVyQ29sb3IiOiJoc2woODAsIDYwJSwgODYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeVRleHRDb2xvciI6IiMxMzEzMDAiLCJzZWNvbmRhcnlUZXh0Q29sb3IiOiIjMDAwMDIxIiwidGVydGlhcnlUZXh0Q29sb3IiOiJyZ2IoOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEsIDkuNTAwMDAwMDAwMSkiLCJsaW5lQ29sb3IiOiIjMzMzMzMzIiwidGV4dENvbG9yIjoiIzMzMyIsIm1haW5Ca2ciOiIjRUNFQ0ZGIiwic2Vjb25kQmtnIjoiI2ZmZmZkZSIsImJvcmRlcjEiOiIjOTM3MERCIiwiYm9yZGVyMiI6IiNhYWFhMzMiLCJhcnJvd2hlYWRDb2xvciI6IiMzMzMzMzMiLCJmb250RmFtaWx5IjoiXCJ0cmVidWNoZXQgbXNcIiwgdmVyZGFuYSwgYXJpYWwiLCJmb250U2l6ZSI6IjE2cHgiLCJsYWJlbEJhY2tncm91bmQiOiIjZThlOGU4Iiwibm9kZUJrZyI6IiNFQ0VDRkYiLCJub2RlQm9yZGVyIjoiIzkzNzBEQiIsImNsdXN0ZXJCa2ciOiIjZmZmZmRlIiwiY2x1c3RlckJvcmRlciI6IiNhYWFhMzMiLCJkZWZhdWx0TGlua0NvbG9yIjoiIzMzMzMzMyIsInRpdGxlQ29sb3IiOiIjMzMzIiwiZWRnZUxhYmVsQmFja2dyb3VuZCI6IiNlOGU4ZTgiLCJhY3RvckJvcmRlciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImFjdG9yQmtnIjoiI0VDRUNGRiIsImFjdG9yVGV4dENvbG9yIjoiYmxhY2siLCJhY3RvckxpbmVDb2xvciI6ImdyZXkiLCJzaWduYWxDb2xvciI6IiMzMzMiLCJzaWduYWxUZXh0Q29sb3IiOiIjMzMzIiwibGFiZWxCb3hCa2dDb2xvciI6IiNFQ0VDRkYiLCJsYWJlbEJveEJvcmRlckNvbG9yIjoiaHNsKDI1OS42MjYxNjgyMjQzLCA1OS43NzY1MzYzMTI4JSwgODcuOTAxOTYwNzg0MyUpIiwibGFiZWxUZXh0Q29sb3IiOiJibGFjayIsImxvb3BUZXh0Q29sb3IiOiJibGFjayIsIm5vdGVCb3JkZXJDb2xvciI6IiNhYWFhMzMiLCJub3RlQmtnQ29sb3IiOiIjZmZmNWFkIiwibm90ZVRleHRDb2xvciI6ImJsYWNrIiwiYWN0aXZhdGlvbkJvcmRlckNvbG9yIjoiIzY2NiIsImFjdGl2YXRpb25Ca2dDb2xvciI6IiNmNGY0ZjQiLCJzZXF1ZW5jZU51bWJlckNvbG9yIjoid2hpdGUiLCJzZWN0aW9uQmtnQ29sb3IiOiJyZ2JhKDEwMiwgMTAyLCAyNTUsIDAuNDkpIiwiYWx0U2VjdGlvbkJrZ0NvbG9yIjoid2hpdGUiLCJzZWN0aW9uQmtnQ29sb3IyIjoiI2ZmZjQwMCIsInRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJ0YXNrQmtnQ29sb3IiOiIjOGE5MGRkIiwidGFza1RleHRMaWdodENvbG9yIjoid2hpdGUiLCJ0YXNrVGV4dENvbG9yIjoid2hpdGUiLCJ0YXNrVGV4dERhcmtDb2xvciI6ImJsYWNrIiwidGFza1RleHRPdXRzaWRlQ29sb3IiOiJibGFjayIsInRhc2tUZXh0Q2xpY2thYmxlQ29sb3IiOiIjMDAzMTYzIiwiYWN0aXZlVGFza0JvcmRlckNvbG9yIjoiIzUzNGZiYyIsImFjdGl2ZVRhc2tCa2dDb2xvciI6IiNiZmM3ZmYiLCJncmlkQ29sb3IiOiJsaWdodGdyZXkiLCJkb25lVGFza0JrZ0NvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCb3JkZXJDb2xvciI6ImdyZXkiLCJjcml0Qm9yZGVyQ29sb3IiOiIjZmY4ODg4IiwiY3JpdEJrZ0NvbG9yIjoicmVkIiwidG9kYXlMaW5lQ29sb3IiOiJyZWQiLCJsYWJlbENvbG9yIjoiYmxhY2siLCJlcnJvckJrZ0NvbG9yIjoiIzU1MjIyMiIsImVycm9yVGV4dENvbG9yIjoiIzU1MjIyMiIsImNsYXNzVGV4dCI6IiMxMzEzMDAiLCJmaWxsVHlwZTAiOiIjRUNFQ0ZGIiwiZmlsbFR5cGUxIjoiI2ZmZmZkZSIsImZpbGxUeXBlMiI6ImhzbCgzMDQsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlMyI6ImhzbCgxMjQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNCI6ImhzbCgxNzYsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlNSI6ImhzbCgtNCwgMTAwJSwgOTMuNTI5NDExNzY0NyUpIiwiZmlsbFR5cGU2IjoiaHNsKDgsIDEwMCUsIDk2LjI3NDUwOTgwMzklKSIsImZpbGxUeXBlNyI6ImhzbCgxODgsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSJ9fSwidXBkYXRlRWRpdG9yIjpmYWxzZX0) + +* `Persisten` - interface for target format/protocol(e.g. gson/protobuf) +* `TypeHandlerLibrary` - core class for registering `TypeHandlerFactory`s +* `TypeHandlerFactory` - factory for `TypeHandler`s +* `TypeHandler` - interface for handling convertiong from `` to PersistentData and otherwise. +For serialization you needs `PersistedDataSerializer` implementation + + + +##### Implement your own format/protocol + Just implement `PersistentData` and `PersistedDataSerializer` + Example( `PersistedBoolean` from `inmemory` storage ): + ```java +public class PersistedBoolean extends AbstractPersistedData { + private boolean data; + + public PersistedBoolean(boolean data) { + this.data = data; + } + + @Override + public boolean getAsBoolean() { + return data; + } + + @Override + public boolean isBoolean() { + return true; + } +} + +``` + +##### Implement your own handler for java type +Just implement `TypeHandler` and register it in `TypeHandlerLibrary` + +Example( `BooleanTypeHandler` from coreTypes ): +```java +public class BooleanTypeHandler extends TypeHandler { + + @Override + public PersistedData serializeNonNull(Boolean value, PersistedDataSerializer serializer) { + return serializer.serialize(value); + } + + @Override + public Optional deserialize(PersistedData data) { + if (data.isBoolean()) { + return Optional.of(data.getAsBoolean()); + } + return Optional.empty(); + } + +} +``` + +Or implement `TypeHandlerFactory` and register it in `TypeHandlerLibrary` + \ No newline at end of file diff --git a/subsystems/TypeHandlerLibrary/build.gradle.kts b/subsystems/TypeHandlerLibrary/build.gradle.kts new file mode 100644 index 00000000000..75cc9c68452 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/build.gradle.kts @@ -0,0 +1,25 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +plugins { + java + `java-library` +} + +apply(from = "$rootDir/config/gradle/common.gradle") + +dependencies { + implementation("org.slf4j:slf4j-api:1.7.21") + implementation("net.sf.trove4j:trove4j:3.0.3") + + implementation("org.reflections:reflections:0.9.10") + implementation("org.terasology.nui:nui-reflect:1.3.1") + implementation("org.terasology:gestalt-module:5.1.5") + implementation("org.terasology:gestalt-asset-core:5.1.5") + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.2") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.5.2") + testImplementation("org.mockito:mockito-junit-jupiter:3.2.0") + + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.5.2") +} \ No newline at end of file diff --git a/engine/src/main/java/org/terasology/persistence/serializers/AbstractSerializer.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/serializers/AbstractSerializer.java similarity index 100% rename from engine/src/main/java/org/terasology/persistence/serializers/AbstractSerializer.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/serializers/AbstractSerializer.java diff --git a/engine/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java similarity index 60% rename from engine/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java index 01d57915ed7..6692ea01b2e 100644 --- a/engine/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/serializers/DeserializeFieldCheck.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.serializers; import org.terasology.reflection.metadata.ClassMetadata; diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java new file mode 100644 index 00000000000..a750525b353 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/DeserializationException.java @@ -0,0 +1,26 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling; + +/** + * This exception is thrown when deserializing a type fails + */ +public class DeserializationException extends RuntimeException { + + private static final long serialVersionUID = -6211402729551315020L; + + public DeserializationException() { + } + + public DeserializationException(String message) { + super(message); + } + + public DeserializationException(String message, Throwable cause) { + super(message, cause); + } + + public DeserializationException(Throwable cause) { + super(cause); + } +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java similarity index 60% rename from engine/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java index c23dee529fa..aad114b714e 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/FutureTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import java.util.Optional; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java similarity index 59% rename from engine/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java index 28fde996d09..0c4bb329971 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/InstanceCreator.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import java.lang.reflect.Type; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java similarity index 84% rename from engine/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java index c22869d8ec9..9646e4571e5 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedData.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; @@ -79,7 +66,7 @@ public interface PersistedData { /** * Retrieves this data as a byte array. This requires that the data is bytes. * - * @return this data as a boolean value + * @return this data as a bytes value * @throws DeserializationException if the data is not bytes */ byte[] getAsBytes(); diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java index 8539b8d022a..587b6ae1061 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataArray.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import gnu.trove.list.TDoubleList; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java similarity index 56% rename from engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java index c11077eebf5..c9de234b080 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataMap.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import org.terasology.persistence.typeHandling.inMemory.PersistedMap; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java similarity index 86% rename from engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java index 2c7c7e01175..81b9665677c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/PersistedDataSerializer.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import gnu.trove.iterator.TDoubleIterator; diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java new file mode 100644 index 00000000000..c35117489be --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SerializationException.java @@ -0,0 +1,26 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling; + +/** + * This exception is thrown when deserializing a type fails + */ +public class SerializationException extends RuntimeException { + + private static final long serialVersionUID = -9046087332035665508L; + + public SerializationException() { + } + + public SerializationException(String message) { + super(message); + } + + public SerializationException(String message, Throwable cause) { + super(message, cause); + } + + public SerializationException(Throwable cause) { + super(cause); + } +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/Serializer.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/Serializer.java similarity index 90% rename from engine/src/main/java/org/terasology/persistence/typeHandling/Serializer.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/Serializer.java index 17ffc15c526..2ee17a81b92 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/Serializer.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/Serializer.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import org.slf4j.Logger; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java similarity index 66% rename from engine/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java index 0655295bb32..8ed561245f2 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/SpecificTypeHandlerFactory.java @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import org.terasology.reflection.TypeInfo; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java index 8f8b08409da..57dd3977240 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/StringRepresentationTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import java.util.Optional; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java similarity index 87% rename from engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java index c53f2fa8657..3302bed812c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import java.util.Optional; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java similarity index 68% rename from engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java index cc91f2c064f..93dbdcd53f2 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerContext.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java similarity index 70% rename from engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java index c266f369846..32244257875 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerFactory.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import org.terasology.reflection.TypeInfo; diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java new file mode 100644 index 00000000000..664894d22f1 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java @@ -0,0 +1,327 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.reflections.Reflections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.persistence.typeHandling.coreTypes.BooleanTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.ByteArrayTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.ByteTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.CharacterTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.DoubleTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.FloatTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.IntTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.LongTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.NumberTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.StringTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.factories.ArrayTypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.factories.CollectionTypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.factories.EnumTypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.factories.ObjectFieldMapTypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.factories.StringMapTypeHandlerFactory; +import org.terasology.persistence.typeHandling.reflection.ReflectionsSandbox; +import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; +import org.terasology.reflection.TypeInfo; +import org.terasology.reflection.metadata.ClassMetadata; +import org.terasology.reflection.metadata.FieldMetadata; +import org.terasology.reflection.reflect.ConstructorLibrary; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * A library of type handlers. This is used for the construction of class metadata. This library should be initialised + * by adding a number of base type handlers, describing how to serialize each supported type. It will then produce + * serializers for classes (through their ClassMetadata) on request. + */ +public class TypeHandlerLibrary { + private static final Logger logger = LoggerFactory.getLogger(TypeHandlerLibrary.class); + /** + * In certain object graphs, creating a {@link TypeHandler} for a type may recursively require an {@link + * TypeHandler} for the same type. Without intervention, the recursive lookup would stack overflow. Thus, for type + * handlers in the process of being created, we return a delegate to the {@link TypeHandler} via {@link + * FutureTypeHandler} which is wired after the {@link TypeHandler} has been created. + */ + private final ThreadLocal, FutureTypeHandler>> futureTypeHandlers = new ThreadLocal<>(); + private final SerializationSandbox sandbox; + private final List typeHandlerFactories = Lists.newArrayList(); + private final Map> instanceCreators = Maps.newHashMap(); + private final Map, TypeHandler> typeHandlerCache = Maps.newHashMap(); + private final Map, Serializer> serializerMap = Maps.newHashMap(); + + protected TypeHandlerLibrary(SerializationSandbox sandbox) { + this.sandbox = sandbox; + ConstructorLibrary constructorLibrary = new ConstructorLibrary(instanceCreators); + addTypeHandlerFactory(new ObjectFieldMapTypeHandlerFactory(constructorLibrary)); + TypeHandlerLibrary.populateBuiltInHandlers(this); + addTypeHandlerFactory(new CollectionTypeHandlerFactory(constructorLibrary)); + } + + + /** + * + */ + public TypeHandlerLibrary(Reflections reflections) { + this(new ReflectionsSandbox(reflections)); + } + + /** + * Constructor for copying. + */ + private TypeHandlerLibrary(List typeHandlerFactories, + Map> instanceCreators, SerializationSandbox sandbox) { + this.typeHandlerFactories.addAll(typeHandlerFactories); + this.instanceCreators.putAll(instanceCreators); + this.sandbox = sandbox; + } + + static void populateBuiltInHandlers(TypeHandlerLibrary typeHandlerLibrary) { + typeHandlerLibrary.addTypeHandler(Boolean.class, new BooleanTypeHandler()); + typeHandlerLibrary.addTypeHandler(Boolean.TYPE, new BooleanTypeHandler()); + typeHandlerLibrary.addTypeHandler(Byte.class, new ByteTypeHandler()); + typeHandlerLibrary.addTypeHandler(Byte.TYPE, new ByteTypeHandler()); + typeHandlerLibrary.addTypeHandler(Character.class, new CharacterTypeHandler()); + typeHandlerLibrary.addTypeHandler(Character.TYPE, new CharacterTypeHandler()); + typeHandlerLibrary.addTypeHandler(Double.class, new DoubleTypeHandler()); + typeHandlerLibrary.addTypeHandler(Double.TYPE, new DoubleTypeHandler()); + typeHandlerLibrary.addTypeHandler(Float.class, new FloatTypeHandler()); + typeHandlerLibrary.addTypeHandler(Float.TYPE, new FloatTypeHandler()); + typeHandlerLibrary.addTypeHandler(Integer.class, new IntTypeHandler()); + typeHandlerLibrary.addTypeHandler(Integer.TYPE, new IntTypeHandler()); + typeHandlerLibrary.addTypeHandler(Long.class, new LongTypeHandler()); + typeHandlerLibrary.addTypeHandler(Long.TYPE, new LongTypeHandler()); + typeHandlerLibrary.addTypeHandler(String.class, new StringTypeHandler()); + typeHandlerLibrary.addTypeHandler(Number.class, new NumberTypeHandler()); + + typeHandlerLibrary.addTypeHandlerFactory(new ArrayTypeHandlerFactory()); + typeHandlerLibrary.addTypeHandler(byte[].class, new ByteArrayTypeHandler()); + + typeHandlerLibrary.addTypeHandlerFactory(new EnumTypeHandlerFactory()); + typeHandlerLibrary.addTypeHandlerFactory(new StringMapTypeHandlerFactory()); + } + + /** + * Creates a copy of an this serialization library. This copy is initialised with all type handlers that were added + * to the original, but does not retain any serializers or type handlers that were generated. This can be used to + * override specific types handlers from another type serializer. + */ + public TypeHandlerLibrary copy() { + return new TypeHandlerLibrary(this.typeHandlerFactories, this.instanceCreators, sandbox); + } + + /** + * Obtains a serializer for the given type + * + * @param type The ClassMetadata for the type of interest + * @return A serializer for serializing/deserializing the type + */ + public Serializer getSerializerFor(ClassMetadata type) { + Serializer serializer = serializerMap.get(type); + if (serializer == null) { + Map, TypeHandler> fieldHandlerMap = getFieldHandlerMap(type); + serializer = new Serializer(type, fieldHandlerMap); + serializerMap.put(type, serializer); + } + return serializer; + } + + /** + * Adds a new {@link TypeHandlerFactory} to the {@link TypeHandlerLibrary}. Factories added later are given a higher + * priority during {@link TypeHandler} generation. + */ + public void addTypeHandlerFactory(TypeHandlerFactory typeHandlerFactory) { + typeHandlerFactories.add(typeHandlerFactory); + } + + /** + * Adds a {@link TypeHandler} for the specified type to this {@link TypeHandlerLibrary} by adding to the library a + * new {@link TypeHandlerFactory} that returns the {@link TypeHandler} whenever the {@link TypeHandler} for the + * specified type is requested. + *

+ * If the specified {@link SerializationSandbox} does not allow the addition of the given {@link TypeHandler} for + * the given type, the {@link TypeHandler} is not added to the library and false is returned. + * + * @param typeClass The {@link Class} of the type handled by the {@link TypeHandler}. + * @param typeHandler The {@link TypeHandler} to add to the library. + * @param The type handled by the {@link TypeHandler}. + * @return True if the {@link TypeHandler} was successfully added, false otherwise. + */ + public boolean addTypeHandler(Class typeClass, TypeHandler typeHandler) { + return addTypeHandler(TypeInfo.of(typeClass), typeHandler); + } + + /** + * Adds a {@link TypeHandler} for the specified type to this {@link TypeHandlerLibrary} by adding to the library a + * new {@link TypeHandlerFactory} that returns the {@link TypeHandler} whenever the {@link TypeHandler} for the + * specified type is requested. + *

+ * If the specified {@link SerializationSandbox} does not allow the addition of the given {@link TypeHandler} for + * the given type, the {@link TypeHandler} is not added to the library and false is returned. + * + * @param The type handled by the {@link TypeHandler}. + * @param type The {@link TypeInfo} of the type handled by the {@link TypeHandler}. + * @param typeHandler The {@link TypeHandler} to add to the library. + * @return True if the {@link TypeHandler} was successfully added, false otherwise. + */ + public boolean addTypeHandler(TypeInfo type, TypeHandler typeHandler) { + if (!sandbox.isValidTypeHandlerDeclaration(type, typeHandler)) { + return false; + } + + addTypeHandlerFactory(new SpecificTypeHandlerFactory(type) { + @Override + protected TypeHandler createHandler(TypeHandlerContext context) { + return typeHandler; + } + }); + + return true; + } + + /** + * Adds an {@link InstanceCreator} to the {@link TypeHandlerLibrary} for the specified type. + */ + public void addInstanceCreator(Class typeClass, InstanceCreator instanceCreator) { + addInstanceCreator(TypeInfo.of(typeClass), instanceCreator); + } + + /** + * Adds an {@link InstanceCreator} to the {@link TypeHandlerLibrary} for the specified type. + */ + public void addInstanceCreator(TypeInfo typeInfo, InstanceCreator instanceCreator) { + instanceCreators.put(typeInfo.getType(), instanceCreator); + } + + /** + * Retrieves the {@link TypeHandler} for the specified type, if available. + *

+ * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested to generate a {@link + * TypeHandler} for the given type. Most recently added factories are requested first, hence a {@link + * TypeHandlerFactory} can override one that was added before it. + * + * @param type The {@link Type} describing the type for which to retrieve the {@link TypeHandler}. + * @return The {@link TypeHandler} for the specified type, if available. + */ + @SuppressWarnings({"unchecked"}) + public Optional> getTypeHandler(Type type) { + TypeInfo typeInfo = TypeInfo.of(type); + return (Optional>) getTypeHandler(typeInfo); + } + + /** + * Retrieves the {@link TypeHandler} for the specified type, if available. + *

+ * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested to generate a {@link + * TypeHandler} for the given type. Most recently added factories are requested first, hence a {@link + * TypeHandlerFactory} can override one that was added before it. + * + * @param typeClass The {@link Class} of the type for which to retrieve the {@link TypeHandler}. + * @param The type for which to retrieve the {@link TypeHandler}. + * @return The {@link TypeHandler} for the specified type, if available. + */ + public Optional> getTypeHandler(Class typeClass) { + return getTypeHandler(TypeInfo.of(typeClass)); + } + + /** + * Retrieves the {@link TypeHandler} for the specified type, if available. + *

+ * Each {@link TypeHandlerFactory} added to this {@link TypeHandlerLibrary} is requested to generate a {@link + * TypeHandler} for the given type. Most recently added factories are requested first, hence a {@link + * TypeHandlerFactory} can override one that was added before it. + * + * @param type The {@link TypeInfo} describing the type for which to retrieve the {@link TypeHandler}. + * @param The type for which to retrieve the {@link TypeHandler}. + * @return The {@link TypeHandler} for the specified type, if available. + */ + @SuppressWarnings("unchecked") + public Optional> getTypeHandler(TypeInfo type) { + TypeHandlerContext context = new TypeHandlerContext(this, sandbox); + + if (typeHandlerCache.containsKey(type)) { + return Optional.of((TypeHandler) typeHandlerCache.get(type)); + } + + Map, FutureTypeHandler> futures = futureTypeHandlers.get(); + boolean cleanupFutureTypeHandlers = false; + + if (futures == null) { + cleanupFutureTypeHandlers = true; + futures = new HashMap<>(); + futureTypeHandlers.set(futures); + } + + FutureTypeHandler future = (FutureTypeHandler) futures.get(type); + + if (future != null) { + return Optional.of(future); + } + + try { + future = new FutureTypeHandler<>(); + futures.put(type, future); + + // TODO: Explore reversing typeHandlerFactories itself before building object + for (int i = typeHandlerFactories.size() - 1; i >= 0; i--) { + TypeHandlerFactory typeHandlerFactory = typeHandlerFactories.get(i); + Optional> typeHandler = typeHandlerFactory.create(type, context); + + if (typeHandler.isPresent()) { + TypeHandler handler = typeHandler.get(); + + if (!sandbox.isValidTypeHandlerDeclaration(type, handler)) { + continue; + } + + typeHandlerCache.put(type, handler); + future.typeHandler = handler; + + return Optional.of(handler); + } + } + + return Optional.empty(); + } finally { + futures.remove(type); + + if (cleanupFutureTypeHandlers) { + futureTypeHandlers.remove(); + } + } + } + + /** + * Returns a {@link TypeHandler} that can handle all types deriving from {@link T}. + * + * @param typeInfo The {@link TypeInfo} describing the base type for which to return a {@link TypeHandler}. + * @param The base type for which to return a {@link TypeHandler}. + */ + public TypeHandler getBaseTypeHandler(TypeInfo typeInfo) { + TypeHandler delegateHandler = getTypeHandler(typeInfo).orElse(null); + + TypeHandlerContext context = new TypeHandlerContext(this, sandbox); + return new RuntimeDelegatingTypeHandler<>(delegateHandler, typeInfo, context); + } + + private Map, TypeHandler> getFieldHandlerMap(ClassMetadata type) { + Map, TypeHandler> handlerMap = Maps.newHashMap(); + for (FieldMetadata field : type.getFields()) { + Optional> handler = getTypeHandler(field.getField().getGenericType()); + + if (handler.isPresent()) { + handlerMap.put(field, handler.get()); + } else { + logger.error("Unsupported field: '{}.{}'", type.getUri(), field.getName()); + } + } + return handlerMap; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java new file mode 100644 index 00000000000..1c320f87dd2 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/annotations/SerializedName.java @@ -0,0 +1,21 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An annotation that indicates that the decorated field should be serialized with + * the provided name value as its field name. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface SerializedName { + /** + * @return the desired name of the field when it is serialized or deserialized. + */ + String value(); +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java similarity index 79% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java index e7f86be1719..88fe82ea51c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Lists; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java similarity index 55% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java index dd05b9311b5..cdd4b1f4221 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/BooleanTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java index 0c04a6f39ff..b3003ba56d4 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteArrayTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java similarity index 58% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java index d9429609687..95cba9ffda1 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ByteTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java similarity index 60% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java index 1805e44cc2c..5ce84041faa 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java similarity index 73% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java index f160ab0e153..100ad88387d 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Lists; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java index 9ed0d6b77f1..2de4cb89b72 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/DoubleTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java similarity index 72% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java index 0eb8ae6d2bc..92cc05cf1ea 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Maps; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java index 869d89aeb15..2599de7ed0c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/FloatTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java index 0047a84acb5..f68b6ce2aec 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/IntTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java similarity index 54% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java index 287375681da..993d9c87824 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/LongTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java similarity index 55% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java index 2b979fc6664..be2daae2ec5 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/NumberTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java similarity index 87% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java index b524383b7e3..8fee0d85cb3 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/ObjectFieldMapTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.base.Defaults; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java similarity index 93% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java index 7ac4a3ff57b..c8995948e52 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Maps; @@ -25,8 +12,8 @@ import org.terasology.persistence.typeHandling.TypeHandlerContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; +import org.terasology.reflection.ReflectionUtil; import org.terasology.reflection.TypeInfo; -import org.terasology.utilities.ReflectionUtil; import java.lang.reflect.Type; import java.util.Map; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java similarity index 73% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java index f03c4e50c4e..97f50b187b5 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringMapTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Maps; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java similarity index 55% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java index eb8b910789a..5cfb0189eab 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/StringTypeHandler.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java similarity index 75% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java index 15ccaf3a95e..77aaacd017c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactory.java @@ -1,23 +1,10 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerContext; +import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.ArrayTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; import org.terasology.reflection.TypeInfo; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java similarity index 79% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java index b2da254ae54..9d910d01a01 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactory.java @@ -1,31 +1,18 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerContext; +import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.CollectionTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; +import org.terasology.reflection.ReflectionUtil; import org.terasology.reflection.TypeInfo; import org.terasology.reflection.reflect.ConstructorLibrary; import org.terasology.reflection.reflect.ObjectConstructor; -import org.terasology.utilities.ReflectionUtil; import java.lang.reflect.Type; import java.util.Collection; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java similarity index 64% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java index ffee059f06a..0d1ab0cd0bb 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactory.java @@ -1,23 +1,10 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerContext; +import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.EnumTypeHandler; import org.terasology.reflection.TypeInfo; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java similarity index 85% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java index a9b0bc85944..ec865ccd02b 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactory.java @@ -1,31 +1,18 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import com.google.common.collect.Maps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerContext; +import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.ObjectFieldMapTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; +import org.terasology.reflection.ReflectionUtil; import org.terasology.reflection.TypeInfo; import org.terasology.reflection.reflect.ConstructorLibrary; -import org.terasology.utilities.ReflectionUtil; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java similarity index 75% rename from engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java index 7b214620d96..bb6fc89f640 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java @@ -1,29 +1,16 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.TypeHandlerContext; +import org.terasology.persistence.typeHandling.TypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.StringMapTypeHandler; +import org.terasology.reflection.ReflectionUtil; import org.terasology.reflection.TypeInfo; -import org.terasology.utilities.ReflectionUtil; import java.lang.reflect.Type; import java.util.Map; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java similarity index 78% rename from engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java index 5780a0ef7fd..c1319389ee2 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/AbstractPersistedData.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.inMemory; import org.terasology.persistence.typeHandling.DeserializationException; diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/InMemoryPersistedDataSerializer.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/InMemoryPersistedDataSerializer.java new file mode 100644 index 00000000000..cc33386eefc --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/InMemoryPersistedDataSerializer.java @@ -0,0 +1,168 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory; + +import com.google.common.collect.Lists; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.list.array.TDoubleArrayList; +import gnu.trove.list.array.TFloatArrayList; +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.list.array.TLongArrayList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.PersistedDataSerializer; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedBooleanArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedDoubleArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedFloatArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedIntegerArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedLongArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedStringArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedValueArray; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Map; + +public class InMemoryPersistedDataSerializer implements PersistedDataSerializer { + + public static final PersistedData NULL = new AbstractPersistedData() { + @Override + public boolean isNull() { + return true; + } + }; + + @Override + public PersistedData serialize(String value) { + return new PersistedString(value); + } + + @Override + public PersistedData serialize(String... values) { + return serializeStrings(Arrays.asList(values)); + } + + @Override + public PersistedData serializeStrings(Iterable value) { + return new PersistedStringArray(Lists.newArrayList(value)); + } + + @Override + public PersistedData serialize(float value) { + return new PersistedFloat(value); + } + + @Override + public PersistedData serialize(float... values) { + return new PersistedFloatArray(TFloatArrayList.wrap(values)); + } + + @Override + public PersistedData serialize(TFloatIterator value) { + TFloatArrayList data = new TFloatArrayList(); + while (value.hasNext()) { + data.add(value.next()); + } + return new PersistedFloatArray(data); + } + + @Override + public PersistedData serialize(int value) { + return new PersistedInteger(value); + } + + @Override + public PersistedData serialize(int... values) { + return new PersistedIntegerArray(TIntArrayList.wrap(values)); + } + + @Override + public PersistedData serialize(TIntIterator value) { + TIntArrayList data = new TIntArrayList(); + while (value.hasNext()) { + data.add(value.next()); + } + return new PersistedIntegerArray(data); + } + + @Override + public PersistedData serialize(long value) { + return new PersistedLong(value); + } + + @Override + public PersistedData serialize(long... values) { + return new PersistedLongArray(TLongArrayList.wrap(values)); + } + + @Override + public PersistedData serialize(TLongIterator value) { + TLongArrayList data = new TLongArrayList(); + while (value.hasNext()) { + data.add(value.next()); + } + return new PersistedLongArray(data); + } + + @Override + public PersistedData serialize(boolean value) { + return new PersistedBoolean(value); + } + + @Override + public PersistedData serialize(boolean... values) { + return new PersistedBooleanArray(values); + } + + @Override + public PersistedData serialize(double value) { + return new PersistedDouble(value); + } + + @Override + public PersistedData serialize(double... values) { + return new PersistedDoubleArray(TDoubleArrayList.wrap(values)); + } + + @Override + public PersistedData serialize(TDoubleIterator value) { + TDoubleArrayList data = new TDoubleArrayList(); + while (value.hasNext()) { + data.add(value.next()); + } + return new PersistedDoubleArray(data); + } + + @Override + public PersistedData serialize(byte[] value) { + return new PersistedBytes(value); + } + + @Override + public PersistedData serialize(ByteBuffer value) { + return serialize(value.array()); + } + + @Override + public PersistedData serialize(PersistedData... values) { + return new PersistedValueArray(Arrays.asList(values)); + } + + @Override + public PersistedData serialize(Iterable data) { + return new PersistedValueArray(Lists.newArrayList(data)); + } + + @Override + public PersistedData serialize(Map data) { + return new PersistedMap(data); + } + + @Override + public PersistedData serializeNull() { + return NULL; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java new file mode 100644 index 00000000000..38f2159d960 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBoolean.java @@ -0,0 +1,23 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedBoolean extends AbstractPersistedData { + private boolean data; + + public PersistedBoolean(boolean data) { + this.data = data; + } + + @Override + public boolean getAsBoolean() { + return data; + } + + @Override + public boolean isBoolean() { + return true; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBytes.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBytes.java new file mode 100644 index 00000000000..06aaeeefd0b --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedBytes.java @@ -0,0 +1,30 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory; + +import java.nio.ByteBuffer; + +public class PersistedBytes extends AbstractPersistedData { + + private final byte[] bytes; + + public PersistedBytes(byte[] bytes) { + this.bytes = bytes; + } + + @Override + public byte[] getAsBytes() { + return bytes; + } + + @Override + public ByteBuffer getAsByteBuffer() { + return ByteBuffer.wrap(bytes); + } + + @Override + public boolean isBytes() { + return true; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java new file mode 100644 index 00000000000..f4f1e8d3a16 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedDouble.java @@ -0,0 +1,33 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedDouble extends PersistedNumber { + private double data; + + public PersistedDouble(double data) { + this.data = data; + } + + @Override + public double getAsDouble() { + return data; + } + + @Override + public float getAsFloat() { + return (float) data; + } + + @Override + public int getAsInteger() { + return (int) data; + } + + @Override + public long getAsLong() { + return (long) data; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java new file mode 100644 index 00000000000..fb3dee2bd3c --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedFloat.java @@ -0,0 +1,34 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedFloat extends PersistedNumber { + + private float data; + + public PersistedFloat(float data) { + this.data = data; + } + + @Override + public double getAsDouble() { + return data; + } + + @Override + public float getAsFloat() { + return data; + } + + @Override + public int getAsInteger() { + return (int) data; + } + + @Override + public long getAsLong() { + return (long) data; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java new file mode 100644 index 00000000000..323a4b9af8c --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedInteger.java @@ -0,0 +1,33 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedInteger extends PersistedNumber { + private int data; + + public PersistedInteger(int data) { + this.data = data; + } + + @Override + public double getAsDouble() { + return data; + } + + @Override + public float getAsFloat() { + return data; + } + + @Override + public int getAsInteger() { + return data; + } + + @Override + public long getAsLong() { + return data; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java new file mode 100644 index 00000000000..5a5954ae99a --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedLong.java @@ -0,0 +1,33 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedLong extends PersistedNumber { + private long data; + + public PersistedLong(long data) { + this.data = data; + } + + @Override + public double getAsDouble() { + return data; + } + + @Override + public float getAsFloat() { + return data; + } + + @Override + public int getAsInteger() { + return (int) data; + } + + @Override + public long getAsLong() { + return data; + } +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java similarity index 75% rename from engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java index 17401f21753..d61afd3d102 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedMap.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.inMemory; import org.terasology.persistence.typeHandling.PersistedData; diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java new file mode 100644 index 00000000000..02ea3f051e3 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedNumber.java @@ -0,0 +1,25 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public abstract class PersistedNumber extends AbstractPersistedData { + + @Override + public boolean isNumber() { + return true; + } + + @Override + public abstract double getAsDouble(); + + @Override + public abstract float getAsFloat(); + + @Override + public abstract int getAsInteger(); + + @Override + public abstract long getAsLong(); +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java new file mode 100644 index 00000000000..2518f4712df --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/PersistedString.java @@ -0,0 +1,25 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.persistence.typeHandling.inMemory; + +/** + */ +public class PersistedString extends AbstractPersistedData { + + private String data; + + public PersistedString(String data) { + this.data = data; + } + + @Override + public String getAsString() { + return data; + } + + @Override + public boolean isString() { + return true; + } + +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/AbstractPersistedArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/AbstractPersistedArray.java new file mode 100644 index 00000000000..0c86902e7ec --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/AbstractPersistedArray.java @@ -0,0 +1,78 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import com.google.common.collect.Lists; +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.PersistedDataArray; +import org.terasology.persistence.typeHandling.inMemory.AbstractPersistedData; + +import java.util.List; + +public abstract class AbstractPersistedArray extends AbstractPersistedData implements PersistedDataArray { + + @Override + public PersistedDataArray getAsArray() { + return this; + } + + @Override + public boolean isArray() { + return true; + } + + @Override + public boolean isNumberArray() { + return false; + } + + @Override + public boolean isBooleanArray() { + return false; + } + + @Override + public boolean isStringArray() { + return false; + } + + @Override + public List getAsStringArray() { + throw new ClassCastException("Data Array is not a String Array"); + } + + @Override + public TDoubleList getAsDoubleArray() { + throw new ClassCastException("Data Array is not a Double Array"); + } + + @Override + public TFloatList getAsFloatArray() { + throw new ClassCastException("Data Array is not a Float Array"); + } + + @Override + public TIntList getAsIntegerArray() { + throw new ClassCastException("Data Array is not a Integer Array"); + } + + @Override + public TLongList getAsLongArray() { + throw new ClassCastException("Data Array is not a Long Array"); + } + + @Override + public List getAsValueArray() { + return Lists.newArrayList(iterator()); + } + + @Override + public boolean[] getAsBooleanArray() { + throw new ClassCastException("Data Array is not a Boolean Array"); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedBooleanArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedBooleanArray.java new file mode 100644 index 00000000000..3c5193eacf4 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedBooleanArray.java @@ -0,0 +1,58 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedBoolean; + +import java.util.Arrays; +import java.util.Iterator; + +public class PersistedBooleanArray extends AbstractPersistedArray { + + private final boolean[] booleans; + + public PersistedBooleanArray(boolean[] booleans) { + this.booleans = booleans; + } + + + @Override + public int size() { + return booleans.length; + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedBoolean(booleans[index]); + } + + @Override + public boolean isBooleanArray() { + return true; + } + + @Override + public boolean[] getAsBooleanArray() { + return booleans; + } + + @Override + public Iterator iterator() { + return new Iterator() { + final boolean[] bools = Arrays.copyOf(booleans, booleans.length); + int index = 0; + + @Override + public boolean hasNext() { + return index < bools.length; + } + + @Override + public PersistedData next() { + return new PersistedBoolean(bools[index++]); + } + }; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedDoubleArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedDoubleArray.java new file mode 100644 index 00000000000..e3bd7f8e8fa --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedDoubleArray.java @@ -0,0 +1,63 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedDouble; + +import java.util.Iterator; + +public class PersistedDoubleArray extends PersistedNumberArray { + + private final TDoubleList data; + + public PersistedDoubleArray(TDoubleList data) { + this.data = data; + } + + @Override + public int size() { + return data.size(); + } + + @Override + public TDoubleList getAsDoubleArray() { + return data; + } + + @Override + public TFloatList getAsFloatArray() { + return TroveUtils.doubleToFloat(data); + } + + @Override + public TIntList getAsIntegerArray() { + return TroveUtils.doubleToInt(data); + } + + @Override + public TLongList getAsLongArray() { + return TroveUtils.doubleToLong(data); + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedDouble(data.get(index)); + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public Iterator iterator() { + return TroveUtils.iteratorFrom(data); + } + +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedFloatArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedFloatArray.java new file mode 100644 index 00000000000..ab8b1a67d20 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedFloatArray.java @@ -0,0 +1,62 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedFloat; + +import java.util.Iterator; + +public class PersistedFloatArray extends PersistedNumberArray { + + private final TFloatList data; + + public PersistedFloatArray(TFloatList data) { + this.data = data; + } + + @Override + public int size() { + return data.size(); + } + + @Override + public TDoubleList getAsDoubleArray() { + return TroveUtils.floatToDouble(data); + } + + @Override + public TFloatList getAsFloatArray() { + return data; + } + + @Override + public TIntList getAsIntegerArray() { + return TroveUtils.floatToInt(data); + } + + @Override + public TLongList getAsLongArray() { + return TroveUtils.floatToLong(data); + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedFloat(data.get(index)); + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public Iterator iterator() { + return TroveUtils.iteratorFrom(data); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedIntegerArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedIntegerArray.java new file mode 100644 index 00000000000..656a48242cc --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedIntegerArray.java @@ -0,0 +1,62 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; + +import java.util.Iterator; + +public class PersistedIntegerArray extends PersistedNumberArray { + + private final TIntList data; + + public PersistedIntegerArray(TIntList data) { + this.data = data; + } + + @Override + public int size() { + return data.size(); + } + + @Override + public TDoubleList getAsDoubleArray() { + return TroveUtils.intToDouble(data); + } + + @Override + public TFloatList getAsFloatArray() { + return TroveUtils.intToFloat(data); + } + + @Override + public TIntList getAsIntegerArray() { + return data; + } + + @Override + public TLongList getAsLongArray() { + return TroveUtils.intToLong(data); + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedInteger(data.get(index)); + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public Iterator iterator() { + return TroveUtils.iteratorFrom(data); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedLongArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedLongArray.java new file mode 100644 index 00000000000..0cfc8ebd64f --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedLongArray.java @@ -0,0 +1,62 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedLong; + +import java.util.Iterator; + +public class PersistedLongArray extends PersistedNumberArray { + + private final TLongList data; + + public PersistedLongArray(TLongList data) { + this.data = data; + } + + @Override + public int size() { + return data.size(); + } + + @Override + public TDoubleList getAsDoubleArray() { + return TroveUtils.longToDouble(data); + } + + @Override + public TFloatList getAsFloatArray() { + return TroveUtils.longToFloat(data); + } + + @Override + public TIntList getAsIntegerArray() { + return TroveUtils.longToInt(data); + } + + @Override + public TLongList getAsLongArray() { + return data; + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedLong(data.get(index)); + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public Iterator iterator() { + return TroveUtils.iteratorFrom(data); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedNumberArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedNumberArray.java new file mode 100644 index 00000000000..757870988f3 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedNumberArray.java @@ -0,0 +1,47 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +public abstract class PersistedNumberArray extends AbstractPersistedArray { + @Override + public double getAsDouble() { + if (size() == 1) { + return getArrayItem(0).getAsDouble(); + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public float getAsFloat() { + if (size() == 1) { + return getArrayItem(0).getAsFloat(); + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public int getAsInteger() { + if (size() == 1) { + return getArrayItem(0).getAsInteger(); + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public long getAsLong() { + if (size() == 1) { + return getArrayItem(0).getAsLong(); + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public boolean isNumberArray() { + return true; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedStringArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedStringArray.java new file mode 100644 index 00000000000..ccaf9cc0db5 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedStringArray.java @@ -0,0 +1,55 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import com.google.common.collect.Lists; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedString; + +import java.util.Iterator; +import java.util.List; + +public class PersistedStringArray extends AbstractPersistedArray { + + private final List data; + + public PersistedStringArray(List data) { + this.data = data; + } + + @Override + public String getAsString() { + if (size() == 1) { + return data.get(0); + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public int size() { + return data.size(); + } + + @Override + public PersistedData getArrayItem(int index) { + return new PersistedString(data.get(index)); + } + + @Override + public List getAsStringArray() { + return Lists.newArrayList(data); + } + + + @Override + public boolean isStringArray() { + return true; + } + + @Override + public Iterator iterator() { + return data.stream().map(PersistedString::new).map(ps -> (PersistedData) ps).iterator(); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedValueArray.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedValueArray.java new file mode 100644 index 00000000000..9619e71ca9c --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/PersistedValueArray.java @@ -0,0 +1,144 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import org.terasology.persistence.typeHandling.DeserializationException; +import org.terasology.persistence.typeHandling.PersistedData; + +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.List; + +public class PersistedValueArray extends AbstractPersistedArray { + + private final List data; + + public PersistedValueArray(List data) { + this.data = data; + } + + @Override + public String getAsString() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isString()) { + return persistedData.getAsString(); + } else if (!isNull()) { + throw new ClassCastException("Data is not a String: " + persistedData.toString()); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + return null; + } + + @Override + public double getAsDouble() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isNumber()) { + return persistedData.getAsDouble(); + } else { + throw new ClassCastException("Data is not a Double"); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public float getAsFloat() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isNumber()) { + return persistedData.getAsFloat(); + } else { + throw new ClassCastException("Data is not a Float"); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public int getAsInteger() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isNumber()) { + return persistedData.getAsInteger(); + } else { + throw new ClassCastException("Data is not a Integer" ); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public long getAsLong() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isNumber()) { + return persistedData.getAsLong(); + } else { + throw new ClassCastException("Data is not a Long"); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public boolean getAsBoolean() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isBoolean()) { + return persistedData.getAsBoolean(); + } else { + throw new ClassCastException("Data is not a Boolean"); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public byte[] getAsBytes() { + if (size() == 1) { + PersistedData persistedData = getArrayItem(0); + if (persistedData.isBytes()) { + return persistedData.getAsBytes(); + } else { + throw new DeserializationException("Data is not a Bytes"); + } + } else { + throw new IllegalStateException("Data is an array of size != 1"); + } + } + + @Override + public ByteBuffer getAsByteBuffer() { + return ByteBuffer.wrap(getAsBytes()); + } + + @Override + public int size() { + return data.size(); + } + + @Override + public PersistedData getArrayItem(int index) { + return data.get(index); + } + + @Override + public List getAsValueArray() { + return data; + } + + @Override + public Iterator iterator() { + return data.iterator(); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/TroveUtils.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/TroveUtils.java new file mode 100644 index 00000000000..87570d60742 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/inMemory/arrays/TroveUtils.java @@ -0,0 +1,228 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.inMemory.arrays; + +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.list.TDoubleList; +import gnu.trove.list.TFloatList; +import gnu.trove.list.TIntList; +import gnu.trove.list.TLongList; +import gnu.trove.list.array.TDoubleArrayList; +import gnu.trove.list.array.TFloatArrayList; +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.list.array.TLongArrayList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.inMemory.PersistedDouble; +import org.terasology.persistence.typeHandling.inMemory.PersistedFloat; +import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; +import org.terasology.persistence.typeHandling.inMemory.PersistedLong; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class TroveUtils { + + private TroveUtils() { + + } + + public static TFloatList intToFloat(TIntList list) { + TFloatList result = new TFloatArrayList(list.size()); + TIntIterator iterator = list.iterator(); + while (iterator.hasNext()) { + int i = iterator.next(); + result.add(i); + } + return result; + } + + public static TFloatList longToFloat(TLongList list) { + TFloatList result = new TFloatArrayList(list.size()); + TLongIterator iterator = list.iterator(); + while (iterator.hasNext()) { + long i = iterator.next(); + result.add(i); + } + return result; + } + + public static TFloatList doubleToFloat(TDoubleList list) { + TFloatList result = new TFloatArrayList(list.size()); + TDoubleIterator iterator = list.iterator(); + while (iterator.hasNext()) { + double i = iterator.next(); + result.add((float) i); + } + return result; + } + + public static TDoubleList intToDouble(TIntList list) { + TDoubleList result = new TDoubleArrayList(list.size()); + TIntIterator iterator = list.iterator(); + while (iterator.hasNext()) { + int i = iterator.next(); + result.add(i); + } + return result; + } + + public static TDoubleList longToDouble(TLongList list) { + TDoubleList result = new TDoubleArrayList(list.size()); + TLongIterator iterator = list.iterator(); + while (iterator.hasNext()) { + long i = iterator.next(); + result.add(i); + } + return result; + } + + public static TDoubleList floatToDouble(TFloatList list) { + TDoubleList result = new TDoubleArrayList(list.size()); + TFloatIterator iterator = list.iterator(); + while (iterator.hasNext()) { + float i = iterator.next(); + result.add(i); + } + return result; + } + + public static TLongList intToLong(TIntList list) { + TLongList result = new TLongArrayList(list.size()); + TIntIterator iterator = list.iterator(); + while (iterator.hasNext()) { + int i = iterator.next(); + result.add(i); + } + return result; + } + + public static TLongList floatToLong(TFloatList list) { + TLongList result = new TLongArrayList(list.size()); + TFloatIterator iterator = list.iterator(); + while (iterator.hasNext()) { + float i = iterator.next(); + result.add((long) i); + } + return result; + } + + public static TLongList doubleToLong(TDoubleList list) { + TLongList result = new TLongArrayList(list.size()); + TDoubleIterator iterator = list.iterator(); + while (iterator.hasNext()) { + double i = iterator.next(); + result.add((long) i); + } + return result; + } + + public static TIntList floatToInt(TFloatList list) { + TIntList result = new TIntArrayList(list.size()); + TFloatIterator iterator = list.iterator(); + while (iterator.hasNext()) { + float i = iterator.next(); + result.add((int) i); + } + return result; + } + + public static TIntList longToInt(TLongList list) { + TIntList result = new TIntArrayList(list.size()); + TLongIterator iterator = list.iterator(); + while (iterator.hasNext()) { + long i = iterator.next(); + result.add((int) i); + } + return result; + } + + public static TIntList doubleToInt(TDoubleList list) { + TIntList result = new TIntArrayList(list.size()); + TDoubleIterator iterator = list.iterator(); + while (iterator.hasNext()) { + double i = iterator.next(); + result.add((int) i); + } + return result; + } + + public static Iterator iteratorFrom(TIntList list) { + return new Iterator() { + private final TIntIterator iterator = list.iterator(); + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public PersistedData next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return new PersistedInteger(iterator.next()); + } + }; + } + + public static Iterator iteratorFrom(TLongList list) { + return new Iterator() { + private final TLongIterator iterator = list.iterator(); + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public PersistedData next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return new PersistedLong(iterator.next()); + } + }; + } + + public static Iterator iteratorFrom(TFloatList list) { + return new Iterator() { + private final TFloatIterator iterator = list.iterator(); + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public PersistedData next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return new PersistedFloat(iterator.next()); + } + }; + } + + public static Iterator iteratorFrom(TDoubleList list) { + return new Iterator() { + private final TDoubleIterator iterator = list.iterator(); + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public PersistedData next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return new PersistedDouble(iterator.next()); + } + }; + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/package-info.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/package-info.java new file mode 100644 index 00000000000..c5a409ec97d --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/package-info.java @@ -0,0 +1,11 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +/** + * This package contains the interfaces and abstract classes for use when defining type handlers. + * Type handlers provide the algorithms for serializing and deserializing types - this uses an implementation agnostic set of interfaces + * so TypeHandlers can be used for different serialization techniques (Json, Protobuf, etc). + */ +@API package org.terasology.persistence.typeHandling; + +import org.terasology.module.sandbox.API; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java similarity index 77% rename from engine/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java index 27209ab42d6..32c77bf3198 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/reflection/ReflectionsSandbox.java @@ -9,6 +9,12 @@ import java.util.Optional; import java.util.Set; +/** + * Provides an interface to the sandboxed environment that serialization may be performed in. + * This allows serialization to load types according to the rules specified in the sandbox it + * is being executed in. + * Uses {@link Reflections} for find and load types. + */ public class ReflectionsSandbox implements SerializationSandbox { private final Reflections reflections; @@ -16,6 +22,9 @@ public ReflectionsSandbox(Reflections reflections) { this.reflections = reflections; } + /** + * {@inheritDoc} + */ @Override public Optional> findSubTypeOf(String subTypeIdentifier, Class clazz) { Set> subTypes = reflections.getSubTypesOf(clazz); @@ -30,6 +39,9 @@ public Optional> findSubTypeOf(String subTypeIdentifier, return Optional.empty(); } + /** + * {@inheritDoc} + */ @Override public boolean isValidTypeHandlerDeclaration(TypeInfo type, TypeHandler typeHandler) { return true; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/reflection/SerializationSandbox.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/reflection/SerializationSandbox.java similarity index 100% rename from engine/src/main/java/org/terasology/persistence/typeHandling/reflection/SerializationSandbox.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/reflection/SerializationSandbox.java diff --git a/engine/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java similarity index 91% rename from engine/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java index 17d22c43534..5f3008aa311 100644 --- a/engine/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/reflection/reflect/ConstructorLibrary.java @@ -1,21 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * Copyright (C) 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Based on Gson v2.6.2 com.google.gson.internal.ConstructorConstructor - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.reflection.reflect; import org.terasology.persistence.typeHandling.InstanceCreator; diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java similarity index 78% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java index 008cc5eee5b..ea12facf8ce 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/FutureTypeHandlerTest.java @@ -1,22 +1,10 @@ -/* - * Copyright 2019 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; import com.google.common.collect.Lists; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.reflections.Reflections; @@ -30,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -38,7 +25,7 @@ public class FutureTypeHandlerTest { private final Reflections reflections = new Reflections(getClass().getClassLoader()); private final TypeHandlerLibrary typeHandlerLibrary = - spy(TypeHandlerLibrary.withReflections(reflections)); + Mockito.spy(new TypeHandlerLibrary(reflections)); private static class RecursiveType { final T data; diff --git a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/InMemorySerializerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/InMemorySerializerTest.java new file mode 100644 index 00000000000..cddcbc07fc9 --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/InMemorySerializerTest.java @@ -0,0 +1,536 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling; + +import gnu.trove.list.array.TDoubleArrayList; +import gnu.trove.list.array.TFloatArrayList; +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.list.array.TLongArrayList; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.internal.util.collections.Sets; +import org.terasology.persistence.typeHandling.inMemory.InMemoryPersistedDataSerializer; +import org.terasology.persistence.typeHandling.inMemory.PersistedBoolean; +import org.terasology.persistence.typeHandling.inMemory.PersistedBytes; +import org.terasology.persistence.typeHandling.inMemory.PersistedDouble; +import org.terasology.persistence.typeHandling.inMemory.PersistedFloat; +import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; +import org.terasology.persistence.typeHandling.inMemory.PersistedLong; +import org.terasology.persistence.typeHandling.inMemory.PersistedString; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedBooleanArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedDoubleArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedFloatArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedIntegerArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedLongArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedStringArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedValueArray; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + + +class InMemorySerializerTest { + private InMemoryPersistedDataSerializer serializer = new InMemoryPersistedDataSerializer(); + + public static Stream types() { + return Stream.of( + Arguments.of(new PersistedInteger(1), + Sets.newSet(TypeGetter.INTEGER, TypeGetter.LONG, TypeGetter.FLOAT, TypeGetter.DOUBLE)), + Arguments.of(new PersistedLong(1), + Sets.newSet(TypeGetter.INTEGER, TypeGetter.LONG, TypeGetter.FLOAT, TypeGetter.DOUBLE)), + Arguments.of(new PersistedFloat(1), + Sets.newSet(TypeGetter.INTEGER, TypeGetter.LONG, TypeGetter.FLOAT, TypeGetter.DOUBLE)), + Arguments.of(new PersistedDouble(1), + Sets.newSet(TypeGetter.INTEGER, TypeGetter.LONG, TypeGetter.FLOAT, TypeGetter.DOUBLE)), + + Arguments.of(new PersistedString("foo"), + Sets.newSet(TypeGetter.STRING)), + + Arguments.of(new PersistedBytes(new byte[]{(byte) 0xFF}), + Sets.newSet(TypeGetter.BYTE_BUFFER, TypeGetter.BYTES)), + Arguments.of(new PersistedBytes(new byte[]{(byte) 0xFF}), + Sets.newSet(TypeGetter.BYTES, TypeGetter.BYTE_BUFFER)), + Arguments.of(new PersistedBoolean(true), + Sets.newSet(TypeGetter.BOOLEAN)) + ); + } + + @Test + void serializeString() { + PersistedData data = serializer.serialize("foo"); + + Assertions.assertEquals(PersistedString.class, data.getClass()); + Assertions.assertTrue(data.isString()); + Assertions.assertEquals("foo", data.getAsString()); + + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + @Test + void serializeStrings() { + PersistedData data = serializer.serialize("foo", "bar"); + Assertions.assertEquals(PersistedStringArray.class, data.getClass()); + + Assertions.assertTrue(data.isArray()); + Assertions.assertEquals("foo", data.getAsArray().getArrayItem(0).getAsString()); + + Assertions.assertTrue(data.getAsArray().isStringArray()); + Assertions.assertEquals("foo", data.getAsArray().getAsStringArray().get(0)); + + Assertions.assertTrue(data.isArray()); + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsString); + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + //TODO remove it + public void template(PersistedData data) { + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + @Test + void serializeOneAsStrings() { + PersistedData data = serializer.serialize(new String[]{"foo"}); + Assertions.assertEquals(PersistedStringArray.class, data.getClass()); + + Assertions.assertEquals("foo", data.getAsString()); + } + + @Test + void serializeStringsIterable() { + PersistedData data = serializer.serializeStrings(Arrays.asList("foo", "bar")); + Assertions.assertEquals(PersistedStringArray.class, data.getClass()); + + Assertions.assertTrue(data.isArray()); + Assertions.assertEquals("foo", data.getAsArray().getArrayItem(0).getAsString()); + + Assertions.assertTrue(data.getAsArray().isStringArray()); + Assertions.assertEquals("foo", data.getAsArray().getAsStringArray().get(0)); + } + + @Test + void serializeOneAsStringsIterable() { + PersistedData data = serializer.serializeStrings(Collections.singleton("foo")); + Assertions.assertEquals(PersistedStringArray.class, data.getClass()); + + Assertions.assertEquals("foo", data.getAsString()); + } + + @Test + void serializeFloat() { + PersistedData data = serializer.serialize(1f); + Assertions.assertEquals(PersistedFloat.class, data.getClass()); + checkIsNumber(data); + } + + @Test + void serializeFloats() { + PersistedData data = serializer.serialize(new float[]{1F}); + checkNumberArray(data, PersistedFloatArray.class, PersistedFloat.class); + } + + @Test + void serializeTFloatIterator() { + PersistedData data = serializer.serialize(TFloatArrayList.wrap(new float[]{1F}).iterator()); + checkNumberArray(data, PersistedFloatArray.class, PersistedFloat.class); + } + + @Test + void serializeInt() { + PersistedData data = serializer.serialize(1); + Assertions.assertEquals(PersistedInteger.class, data.getClass()); + + checkIsNumber(data); + } + + @Test + void serializeInts() { + PersistedData data = serializer.serialize(new int[]{1}); + checkNumberArray(data, PersistedIntegerArray.class, PersistedInteger.class); + } + + @Test + void serializeTIntIterator() { + PersistedData data = serializer.serialize(TIntArrayList.wrap(new int[]{1}).iterator()); + checkNumberArray(data, PersistedIntegerArray.class, PersistedInteger.class); + } + + @Test + void serializeLong() { + PersistedData data = serializer.serialize(1L); + + Assertions.assertEquals(PersistedLong.class, data.getClass()); + + checkIsNumber(data); + } + + @Test + void serializeLongs() { + PersistedData data = serializer.serialize(new long[]{1L}); + checkNumberArray(data, PersistedLongArray.class, PersistedLong.class); + } + + @Test + void serializeTLongIterator() { + PersistedData data = serializer.serialize(TLongArrayList.wrap(new long[]{1L}).iterator()); + checkNumberArray(data, PersistedLongArray.class, PersistedLong.class); + } + + @Test + void serializeBoolean() { + boolean value = true; + PersistedData data = serializer.serialize(value); + + Assertions.assertEquals(PersistedBoolean.class, data.getClass()); + + Assertions.assertTrue(data.isBoolean()); + Assertions.assertEquals(value, data.getAsBoolean()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + @Test + void serializeBooleans() { + PersistedData data = serializer.serialize(new boolean[]{true}); + + Assertions.assertEquals(PersistedBooleanArray.class, data.getClass()); + + checkIsArray(data); + + Assertions.assertTrue(data.getAsArray().isBooleanArray()); + + + Assertions.assertEquals(PersistedBoolean.class, data.getAsArray().getArrayItem(0).getClass()); + } + + @Test + void serializeDouble() { + PersistedData data = serializer.serialize(1D); + Assertions.assertEquals(PersistedDouble.class, data.getClass()); + + checkIsNumber(data); + } + + @Test + void serializeDoubles() { + PersistedData data = serializer.serialize(new double[]{1D}); + checkNumberArray(data, PersistedDoubleArray.class, PersistedDouble.class); + } + + @Test + void serializeTDoubleIterator() { + PersistedData data = serializer.serialize(TDoubleArrayList.wrap(new double[]{1D}).iterator()); + checkNumberArray(data, PersistedDoubleArray.class, PersistedDouble.class); + } + + @Test + void serializeBytes() { + byte[] value = {(byte) 0xFF}; + PersistedData data = serializer.serialize(value); + + Assertions.assertEquals(PersistedBytes.class, data.getClass()); + Assertions.assertTrue(data.isBytes()); + Assertions.assertEquals(value, data.getAsBytes()); + Assertions.assertEquals(ByteBuffer.wrap(value), data.getAsByteBuffer()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + @Test + void serializeByteBuffer() { + byte[] value = {(byte) 0xFF}; + PersistedData data = serializer.serialize(ByteBuffer.wrap(value)); + + Assertions.assertEquals(PersistedBytes.class, data.getClass()); + Assertions.assertTrue(data.isBytes()); + + Assertions.assertEquals(value, data.getAsBytes()); + Assertions.assertEquals(ByteBuffer.wrap(value), data.getAsByteBuffer()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + @ParameterizedTest(name = "{1}") + @MethodSource("types") + void serializePersistedDatas(PersistedData entry, Set typeGetters) { + PersistedData data = serializer.serialize(entry); + checkValueArray(data, entry, typeGetters); + } + + @ParameterizedTest(name = "{1}") + @MethodSource("types") + void serializeIterablePersistedData(PersistedData entry, Set typeGetters) { + PersistedData data = serializer.serialize(Collections.singletonList(entry)); + checkValueArray(data, entry, typeGetters); + } + + @Test + void serializeMapStringPersistedData() { + + } + + @Test + void serializeNull() { + PersistedData data = serializer.serializeNull(); + Assertions.assertSame(InMemoryPersistedDataSerializer.NULL, data); + + Assertions.assertTrue(data.isNull()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + Assertions.assertThrows(ClassCastException.class, data::getAsInteger); + Assertions.assertThrows(ClassCastException.class, data::getAsLong); + Assertions.assertThrows(ClassCastException.class, data::getAsFloat); + Assertions.assertThrows(ClassCastException.class, data::getAsDouble); + } + + private void checkNumberArray(PersistedData data, Class arrayType, + Class entryType) { + Assertions.assertEquals(arrayType, data.getClass()); + + checkIsArray(data); + + Assertions.assertEquals(1, data.getAsInteger()); + Assertions.assertEquals(1L, data.getAsLong()); + Assertions.assertEquals(1F, data.getAsFloat()); + Assertions.assertEquals(1D, data.getAsDouble()); + + Assertions.assertEquals(entryType, data.getAsArray().getArrayItem(0).getClass()); + + Assertions.assertEquals(1, data.getAsArray().getAsIntegerArray().get(0)); + Assertions.assertEquals(1L, data.getAsArray().getAsLongArray().get(0)); + Assertions.assertEquals(1F, data.getAsArray().getAsFloatArray().get(0)); + Assertions.assertEquals(1D, data.getAsArray().getAsDoubleArray().get(0)); + } + + private void checkIsArray(PersistedData data) { + Assertions.assertTrue(data.isArray()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + } + + private void checkIsNumber(PersistedData data) { + Assertions.assertTrue(data.isNumber()); + + Assertions.assertEquals(1, data.getAsInteger()); + Assertions.assertEquals(1L, data.getAsLong()); + Assertions.assertEquals(1F, data.getAsFloat()); + Assertions.assertEquals(1D, data.getAsDouble()); + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isArray()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + Assertions.assertThrows(IllegalStateException.class, data::getAsArray); + + Assertions.assertThrows(DeserializationException.class, data::getAsByteBuffer); + Assertions.assertThrows(DeserializationException.class, data::getAsBytes); + + Assertions.assertThrows(ClassCastException.class, data::getAsString); + Assertions.assertThrows(ClassCastException.class, data::getAsBoolean); + } + + private void checkValueArray(PersistedData data, PersistedData entry, Set typeGetters) { + Assertions.assertEquals(PersistedValueArray.class, data.getClass()); + + Assertions.assertEquals(entry, data.getAsArray().getArrayItem(0)); + typeGetters.stream() + .forEach(typeGetter -> + Assertions.assertEquals(typeGetter.getGetter().apply(entry), + typeGetter.getGetter().apply(data)) + ); + + + Assertions.assertFalse(data.isString()); + Assertions.assertFalse(data.isNull()); + Assertions.assertFalse(data.isNumber()); + Assertions.assertFalse(data.isBoolean()); + Assertions.assertFalse(data.isBytes()); + Assertions.assertFalse(data.isValueMap()); + + Assertions.assertThrows(IllegalStateException.class, data::getAsValueMap); + + Set deserializationExceptionGetters = Sets.newSet( + TypeGetter.BYTE_BUFFER, + TypeGetter.BYTES + ); + deserializationExceptionGetters.stream() + .filter(f -> !typeGetters.contains(f)) + .map(TypeGetter::getGetter) + .map(f -> (Executable) () -> f.apply(data)) + .forEach(e -> + Assertions.assertThrows(DeserializationException.class, e) + ); + + Set classCastExceptionGetters = Sets.newSet( + TypeGetter.BOOLEAN, + TypeGetter.STRING, + TypeGetter.INTEGER, + TypeGetter.LONG, + TypeGetter.FLOAT, + TypeGetter.DOUBLE + ); + classCastExceptionGetters.stream().filter(f -> !typeGetters.contains(f)) + .map(TypeGetter::getGetter) + .map(f -> (Executable) () -> f.apply(data)) + .forEach(e -> + Assertions.assertThrows(ClassCastException.class, e) + ); + } + + private enum TypeGetter { + STRING(PersistedData::getAsString), + BOOLEAN(PersistedData::getAsBoolean), + INTEGER(PersistedData::getAsInteger), + LONG(PersistedData::getAsLong), + FLOAT(PersistedData::getAsFloat), + DOUBLE(PersistedData::getAsDouble), + BYTE_BUFFER(PersistedData::getAsByteBuffer), + BYTES(PersistedData::getAsBytes); + + private final Function getter; + + TypeGetter(Function getter) { + this.getter = getter; + } + + public Function getGetter() { + return getter; + } + } +} diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java similarity index 71% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java index 478074004b9..3a76bd01ceb 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java @@ -1,20 +1,8 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.terasology.persistence.typeHandling.coreTypes.CollectionTypeHandler; @@ -34,22 +22,20 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -public class TypeHandlerLibraryTest { - private final Reflections reflections = new Reflections(getClass().getClassLoader()); - private final TypeHandlerLibrary typeHandlerLibrary = new TypeHandlerLibrary(reflections); +class TypeHandlerLibraryTest { + private static Reflections reflections; + private static TypeHandlerLibrary typeHandlerLibrary; - private enum AnEnum {} + @BeforeAll + public static void setup() { + reflections = new Reflections(TypeHandlerLibraryTest.class.getClassLoader()); + typeHandlerLibrary = new TypeHandlerLibrary(reflections); + TypeHandlerLibrary.populateBuiltInHandlers(typeHandlerLibrary); + } @MappedContainer private static class AMappedContainer {} - @Test - public void testEnumHandler() { - TypeHandler handler = typeHandlerLibrary.getTypeHandler(AnEnum.class).get(); - - assertTrue(handler instanceof EnumTypeHandler); - } - @Test public void testMappedContainerHandler() { TypeHandler handler = typeHandlerLibrary.getTypeHandler(AMappedContainer.class).get(); @@ -76,25 +62,36 @@ public void testCollectionHandler() { } @Test - public void testStringMapHandler() { + void testEnumHandler() { + TypeHandler handler = typeHandlerLibrary.getTypeHandler(AnEnum.class).get(); + + assertTrue(handler instanceof EnumTypeHandler); + } + + @Test + void testStringMapHandler() { TypeHandler> handler = - typeHandlerLibrary.getTypeHandler(new TypeInfo>() {}).get(); + typeHandlerLibrary.getTypeHandler(new TypeInfo>() { + }).get(); assertTrue(handler instanceof StringMapTypeHandler); } @Test - public void testInvalidTypeHandler() { + void testInvalidTypeHandler() { Optional>> handler = - typeHandlerLibrary.getTypeHandler(new TypeInfo>() {}); + typeHandlerLibrary.getTypeHandler(new TypeInfo>() { + }); assertFalse(handler.isPresent()); } @Test - public void testGetBaseTypeHandler() { + void testGetBaseTypeHandler() { TypeHandler handler = typeHandlerLibrary.getBaseTypeHandler(TypeInfo.of(Integer.class)); assertTrue(handler instanceof RuntimeDelegatingTypeHandler); } + + private enum AnEnum {} } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java similarity index 63% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java index 81c882a9cf4..115c3e7872e 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/ArrayTypeHandlerTest.java @@ -1,26 +1,14 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; -import com.google.gson.JsonArray; +import gnu.trove.list.TIntList; +import gnu.trove.list.array.TIntArrayList; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatcher; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataSerializer; -import org.terasology.persistence.typeHandling.gson.GsonPersistedDataArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedIntegerArray; import org.terasology.reflection.TypeInfo; import java.util.Collection; @@ -32,11 +20,11 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -public class ArrayTypeHandlerTest { +class ArrayTypeHandlerTest { private static final int ARRAY_SIZE = 500; @Test - public void testSerialize() { + void testSerialize() { IntTypeHandler elementTypeHandler = mock(IntTypeHandler.class); ArrayTypeHandler typeHandler = new ArrayTypeHandler<>( @@ -59,7 +47,7 @@ public void testSerialize() { } @Test - public void testDeserialize() { + void testDeserialize() { IntTypeHandler elementTypeHandler = mock(IntTypeHandler.class); ArrayTypeHandler typeHandler = new ArrayTypeHandler<>( @@ -67,14 +55,14 @@ public void testDeserialize() { TypeInfo.of(Integer.class) ); - JsonArray jsonArray = new JsonArray(); + TIntList intList = new TIntArrayList(ARRAY_SIZE); for (Integer i : Collections.nCopies(ARRAY_SIZE, -1)) { - jsonArray.add(i); + intList.add(i); } - typeHandler.deserialize(new GsonPersistedDataArray(jsonArray)); + typeHandler.deserialize(new PersistedIntegerArray(intList)); - verify(elementTypeHandler, times(jsonArray.size())).deserialize(any()); + verify(elementTypeHandler, times(intList.size())).deserialize(any()); } } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java similarity index 50% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java index c8bfb7979e3..2936f4b33fa 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CharacterTypeHandlerTest.java @@ -1,22 +1,12 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataSerializer; +import org.terasology.persistence.typeHandling.inMemory.InMemoryPersistedDataSerializer; import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; import org.terasology.persistence.typeHandling.inMemory.PersistedString; @@ -25,26 +15,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -public class CharacterTypeHandlerTest { +class CharacterTypeHandlerTest { CharacterTypeHandler typeHandler = new CharacterTypeHandler(); @Test - public void testSerialize() { - PersistedDataSerializer serializer = mock(PersistedDataSerializer.class); + void testSerialize() { + PersistedDataSerializer serializer = new InMemoryPersistedDataSerializer(); char linefeedChar = '\n'; - typeHandler.serializeNonNull(linefeedChar, serializer); + PersistedData data = typeHandler.serializeNonNull(linefeedChar, serializer); - verify(serializer).serialize(eq("\n")); + Assertions.assertEquals("\n", data.getAsString()); } @Test - public void testDeserialize() { + void testDeserialize() { Optional deserializedLinefeed = typeHandler.deserialize(new PersistedString("\n")); assertTrue(deserializedLinefeed.isPresent()); diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java similarity index 68% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java index 796aacb6c6e..96ab68d14f5 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/CollectionTypeHandlerTest.java @@ -1,28 +1,16 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.Queues; -import com.google.gson.JsonArray; +import gnu.trove.list.TIntList; +import gnu.trove.list.array.TIntArrayList; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatcher; import org.mockito.stubbing.Answer; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataSerializer; -import org.terasology.persistence.typeHandling.gson.GsonPersistedDataArray; +import org.terasology.persistence.typeHandling.inMemory.arrays.PersistedIntegerArray; import org.terasology.reflection.reflect.ObjectConstructor; import java.util.Collection; @@ -35,9 +23,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -public class CollectionTypeHandlerTest { +class CollectionTypeHandlerTest { @Test - public void testSerialize() { + void testSerialize() { IntTypeHandler elementTypeHandler = mock(IntTypeHandler.class); ObjectConstructor> constructor = Queues::newArrayDeque; @@ -65,7 +53,7 @@ public boolean matches(Iterable argument) { } @Test - public void testDeserialize() { + void testDeserialize() { IntTypeHandler elementTypeHandler = mock(IntTypeHandler.class); ObjectConstructor> constructor = mock(ObjectConstructor.class); @@ -76,16 +64,16 @@ public void testDeserialize() { constructor ); - JsonArray jsonArray = new JsonArray(); + TIntList intList = new TIntArrayList(); for (Integer i : Collections.nCopies(500, -1)) { - jsonArray.add(i); + intList.add(i); } - typeHandler.deserialize(new GsonPersistedDataArray(jsonArray)); + typeHandler.deserialize(new PersistedIntegerArray(intList)); verify(constructor).construct(); - verify(elementTypeHandler, times(jsonArray.size())).deserialize(any()); + verify(elementTypeHandler, times(intList.size())).deserialize(any()); } } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java similarity index 70% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java index 83750378f45..6cf7e16194d 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/EnumTypeHandlerSerializerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import org.junit.jupiter.api.Test; @@ -24,16 +11,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -/** - */ -public class EnumTypeHandlerSerializerTest { +class EnumTypeHandlerSerializerTest { enum TestEnum { NON_NULL } @Test - public void testNullValue() throws Exception { + void testNullValue() throws Exception { PersistedData nullData = mock(PersistedData.class); when(nullData.isNull()).thenReturn(true); @@ -47,7 +32,7 @@ public void testNullValue() throws Exception { } @Test - public void testNonNullValue() throws Exception { + void testNonNullValue() throws Exception { PersistedData data = mock(PersistedData.class); when(data.getAsString()).thenReturn(TestEnum.NON_NULL.toString()); when(data.isString()).thenReturn(true); diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java similarity index 89% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java index c6ee1f56b73..db895615b43 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/RuntimeDelegatingTypeHandlerTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes; import com.google.common.collect.ImmutableMap; @@ -43,7 +30,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -public class RuntimeDelegatingTypeHandlerTest { +class RuntimeDelegatingTypeHandlerTest { private final TypeHandlerLibrary typeHandlerLibrary = mock(TypeHandlerLibrary.class); private final TypeHandlerContext context = @@ -99,7 +86,7 @@ private static TypeHandler mockTypeHandler() { } @Test - public void testSerializeBase() { + void testSerializeBase() { PersistedDataSerializer serializer = mock(PersistedDataSerializer.class); when(serializer.serialize(any(String.class))) .then(invocation -> new PersistedString((String) invocation.getArguments()[0])); @@ -122,7 +109,7 @@ public void testSerializeBase() { } @Test - public void testSerializeSub() { + void testSerializeSub() { PersistedDataSerializer serializer = mock(PersistedDataSerializer.class); when(serializer.serialize(any(String.class))) .then(invocation -> new PersistedString((String) invocation.getArguments()[0])); @@ -149,7 +136,7 @@ public void testSerializeSub() { } @Test - public void testDeserializeBase() { + void testDeserializeBase() { setupHandlers(); PersistedData persistedBase = new PersistedMap(ImmutableMap.of()); @@ -163,7 +150,7 @@ public void testDeserializeBase() { } @Test - public void testDeserializeSub() { + void testDeserializeSub() { setupHandlers(); PersistedData persistedSub = new PersistedMap( @@ -185,7 +172,7 @@ public void testDeserializeSub() { } @Test - public void testDeserializeNonSub() { + void testDeserializeNonSub() { setupHandlers(); PersistedData persistedData = new PersistedMap( diff --git a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/SimpleCoreHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/SimpleCoreHandlerTest.java new file mode 100644 index 00000000000..02052c9e5dd --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/SimpleCoreHandlerTest.java @@ -0,0 +1,68 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.coreTypes; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.TypeHandler; +import org.terasology.persistence.typeHandling.inMemory.InMemoryPersistedDataSerializer; +import org.terasology.persistence.typeHandling.inMemory.PersistedBoolean; +import org.terasology.persistence.typeHandling.inMemory.PersistedDouble; +import org.terasology.persistence.typeHandling.inMemory.PersistedFloat; +import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; +import org.terasology.persistence.typeHandling.inMemory.PersistedLong; +import org.terasology.persistence.typeHandling.inMemory.PersistedString; + +import java.lang.reflect.Field; +import java.util.Optional; +import java.util.stream.Stream; + +class SimpleCoreHandlerTest { + + private static Stream primitives() { + return Stream.of( + Arguments.of(true, new BooleanTypeHandler(), new PersistedBoolean(true)), + + Arguments.of(1.0, new NumberTypeHandler(), new PersistedDouble(1)), + Arguments.of(1, new IntTypeHandler(), new PersistedInteger(1)), + Arguments.of(1L, new LongTypeHandler(), new PersistedLong(1)), + Arguments.of(1.0F, new FloatTypeHandler(), new PersistedFloat(1)), + Arguments.of(1.0, new DoubleTypeHandler(), new PersistedDouble(1)), + + Arguments.of("foo", new StringTypeHandler(), new PersistedString("foo")), + Arguments.of('f', new CharacterTypeHandler(), new PersistedString("f"))); + } + + @ParameterizedTest(name = "{1}") + @DisplayName("Check simple core types serialization") + @MethodSource("primitives") + void serialization(T obj, TypeHandler typeHandler, PersistedData expectedData) throws Exception { + PersistedData data = typeHandler.serialize(obj, new InMemoryPersistedDataSerializer()); + + Assertions.assertEquals(expectedData.getClass(), data.getClass()); + Assertions.assertEquals(getData(expectedData), getData(data)); + } + + @ParameterizedTest(name = "{1}") + @DisplayName("Chech simple core types deserialization") + @MethodSource("primitives") + void deserialization(T expectedObj, TypeHandler typeHandler, PersistedData data) throws Exception { + Optional optionalObj = typeHandler.deserialize(data); + Assertions.assertTrue(optionalObj.isPresent()); + T obj = optionalObj.get(); + Assertions.assertEquals(expectedObj.getClass(), obj.getClass()); + Assertions.assertEquals(expectedObj, obj); + } + + private Object getData(PersistedData persistedData) throws Exception { + //I hope that first field - is needs field. + Field dataField = persistedData.getClass().getDeclaredFields()[0]; + dataField.setAccessible(true); + return dataField.get(persistedData); + } +} diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java similarity index 76% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java index cfc1055fb93..cbce33cd65d 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ArrayTypeHandlerFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.junit.jupiter.api.Test; @@ -32,14 +19,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class ArrayTypeHandlerFactoryTest { +class ArrayTypeHandlerFactoryTest { private final TypeHandlerLibrary typeHandlerLibrary = mock(TypeHandlerLibrary.class); private final ArrayTypeHandlerFactory typeHandlerFactory = new ArrayTypeHandlerFactory(); private final TypeHandlerContext context = new TypeHandlerContext(typeHandlerLibrary, mock(SerializationSandbox.class)); @Test - public void testArray() { + void testArray() { TypeInfo arrayTypeInfo = TypeInfo.of(int[].class); Optional> typeHandler = @@ -53,7 +40,7 @@ public void testArray() { } @Test - public void testGenericArray() { + void testGenericArray() { TypeInfo[]> arrayTypeInfo = new TypeInfo[]>() {}; Optional[]>> typeHandler = @@ -67,7 +54,7 @@ public void testGenericArray() { } @Test - public void testNonArray() { + void testNonArray() { TypeInfo> arrayTypeInfo = new TypeInfo>() {}; Optional>> typeHandler = diff --git a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/BytesTypeHandlerTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/BytesTypeHandlerTest.java new file mode 100644 index 00000000000..0e9748f144f --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/BytesTypeHandlerTest.java @@ -0,0 +1,56 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.coreTypes.factories; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.TypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.ByteArrayTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.ByteTypeHandler; +import org.terasology.persistence.typeHandling.inMemory.InMemoryPersistedDataSerializer; +import org.terasology.persistence.typeHandling.inMemory.PersistedBytes; +import org.terasology.persistence.typeHandling.inMemory.PersistedInteger; + +class BytesTypeHandlerTest { + + @Test + void byteSerializeDeserialize() { + byte expectedObj = (byte) 0xFF; + + PersistedBytes data = serialize(expectedObj, new ByteTypeHandler()); + Assertions.assertEquals(expectedObj, data.getAsBytes()[0]); + + byte obj = deserialize(data, new ByteTypeHandler()); + Assertions.assertEquals(expectedObj, obj); + } + + @Test + void intDeserializeAsByte() { + byte expectedObj = (byte) 0xFF; + + byte obj = deserialize(new PersistedInteger(expectedObj), new ByteTypeHandler()); + Assertions.assertEquals(expectedObj, obj); + } + + @Test + void byteArraySerializeDeserialize() { + byte[] expectedObj = new byte[]{(byte) 0xFF}; + + PersistedBytes data = serialize(expectedObj, new ByteArrayTypeHandler()); + Assertions.assertEquals(expectedObj, data.getAsBytes()); + + byte[] obj = deserialize(data, new ByteArrayTypeHandler()); + Assertions.assertEquals(expectedObj, obj); + } + + private R serialize(T obj, TypeHandler typeHandler) { + return (R) typeHandler.serialize(obj, + new InMemoryPersistedDataSerializer()); + } + + private T deserialize(R data, TypeHandler typeHandler) { + return typeHandler.deserializeOrNull(data); + } +} diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java similarity index 85% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java index 5c506470c13..29cf3f900df 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/CollectionTypeHandlerFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import com.google.common.collect.Maps; diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java similarity index 63% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java index 20bcfc1e94e..c21b39c6d6d 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/EnumTypeHandlerFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.junit.jupiter.api.Test; @@ -25,13 +12,13 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -public class EnumTypeHandlerFactoryTest { +class EnumTypeHandlerFactoryTest { private enum SomeEnum { A, B } @Test - public void testEnum() { + void testEnum() { EnumTypeHandlerFactory typeHandlerFactory = new EnumTypeHandlerFactory(); // EnumTypeHandlerFactory does not require a TypeHandlerLibrary Optional> typeHandler = typeHandlerFactory.create(TypeInfo.of(SomeEnum.class), null); @@ -41,7 +28,7 @@ public void testEnum() { } @Test - public void testNonEnum() { + void testNonEnum() { EnumTypeHandlerFactory typeHandlerFactory = new EnumTypeHandlerFactory(); // EnumTypeHandlerFactory does not require a TypeHandlerLibrary diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java similarity index 77% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java index 67a546150ec..1c01157bfac 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/ObjectFieldMapTypeHandlerFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import com.google.common.collect.Maps; diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java similarity index 76% rename from engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java index 23db85875ca..5a6b4d04b02 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2017 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.typeHandling.coreTypes.factories; import org.junit.jupiter.api.Test; @@ -34,7 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class StringMapTypeHandlerFactoryTest { +class StringMapTypeHandlerFactoryTest { private final TypeHandlerLibrary typeHandlerLibrary = mock(TypeHandlerLibrary.class); private final StringMapTypeHandlerFactory typeHandlerFactory = new StringMapTypeHandlerFactory(); @@ -42,7 +29,7 @@ public class StringMapTypeHandlerFactoryTest { new TypeHandlerContext(typeHandlerLibrary, mock(SerializationSandbox.class)); @Test - public void testStringMap() { + void testStringMap() { TypeInfo> listTypeInfo = new TypeInfo>() {}; Optional>> typeHandler = @@ -56,7 +43,7 @@ public void testStringMap() { } @Test - public void testNonStringMap() { + void testNonStringMap() { TypeInfo> listTypeInfo = new TypeInfo>() {}; Optional>> typeHandler = @@ -66,7 +53,7 @@ public void testNonStringMap() { } @Test - public void testNonGenericMap() { + void testNonGenericMap() { class IntMap extends HashMap {} Optional> typeHandler = From feaca854e704ff49e1265ccb41d2e1ad30201692 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 8 Dec 2020 14:34:40 -0800 Subject: [PATCH 017/259] feat(JOML): migrate BlockRegionComponent logic (#4296) Co-authored-by: Tobias Nett --- .../org/terasology/math/BlockRegionTest.java | 130 ++++++++++++++---- .../terasology/world/block/BlockRegion.java | 15 +- .../terasology/world/block/BlockRegions.java | 27 +++- .../world/block/entity/BlockEntitySystem.java | 9 +- .../block/regions/BlockRegionComponent.java | 9 +- .../block/regions/BlockRegionSystem.java | 5 +- .../internal/EntityAwareWorldProvider.java | 24 ++-- 7 files changed, 166 insertions(+), 53 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java index 37e05e09535..d6139650c56 100644 --- a/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java +++ b/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java @@ -1,31 +1,24 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.math; import com.google.common.collect.Sets; +import org.joml.Vector3f; +import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegions; import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -36,7 +29,6 @@ */ public class BlockRegionTest { - @Test public void testCreateRegionWithMinAndSize() { List mins = Arrays.asList(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i(3, 4, 5)); @@ -51,18 +43,50 @@ public void testCreateRegionWithMinAndSize() { } } - @Test - public void testCreateRegionWithMinMax() { - List mins = Arrays.asList(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i(3, 4, 5)); - List expectedSize = Arrays.asList(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(8, 5, - 2)); - List max = Arrays.asList(new Vector3i(), new Vector3i(3, 3, 3), new Vector3i(10, 8, 6)); - for (int i = 0; i < mins.size(); ++i) { - BlockRegion region = new BlockRegion(mins.get(i), max.get(i)); - assertEquals(mins.get(i), region.getMin(new Vector3i())); - assertEquals(max.get(i), region.getMax(new Vector3i())); - assertEquals(expectedSize.get(i), region.getSize(new Vector3i())); - } + private static Stream createFromMinAndMaxArgs() { + return Stream.of( + Arguments.of(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i()), + Arguments.of(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(3, 3, 3)), + Arguments.of(new Vector3i(3, 4, 5), new Vector3i(8, 5, 2), new Vector3i(10, 8, 6)), + Arguments.of(new Vector3i(1, 1, 1), new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), + Arguments.of(new Vector3i(0, 1, 0), new Vector3i(2, 0, 2), new Vector3i(1, 0, 1)) + ); + } + + @ParameterizedTest + @MethodSource("createFromMinAndMaxArgs") + public void createFromMinAndMaxArgs(Vector3i min, Vector3i expectedSize, Vector3i max) { + BlockRegion region = BlockRegions.createFromMinAndMax(min, max); + assertEquals(min, region.getMin(new Vector3i()), "min"); + assertEquals(max, region.getMax(new Vector3i()), "max"); + assertEquals(expectedSize, region.getSize(new Vector3i()), "size"); + } + + private static Stream createEncompassingArgs() { + return Stream.of( + Arguments.of(new Vector3i(1, 1, 1), + new Vector3i[]{new Vector3i(), new Vector3i()}), + Arguments.of(new Vector3i(3, 3, 3), + new Vector3i[]{new Vector3i(1, 1, 1), new Vector3i(3, 3, 3)}), + Arguments.of(new Vector3i(3, 3, 3), + new Vector3i[]{new Vector3i(3, 3, 3), new Vector3i(1, 1, 1)}), + Arguments.of(new Vector3i(2, 2, 2), + new Vector3i[]{new Vector3i(0, 1, 0), new Vector3i(1, 0, 1)}), + Arguments.of(new Vector3i(2, 3, 4), + new Vector3i[]{new Vector3i(0, 1, 0), new Vector3i(1, 0, 1), new Vector3i(0, -1, 3)}) + ); + } + + @ParameterizedTest + @MethodSource("createEncompassingArgs") + public void createEncompassingTest(Vector3i expectedSize, Vector3i[] positions) { + Vector3i min = Arrays.stream(positions).reduce(new Vector3i(Integer.MAX_VALUE), Vector3i::min); + Vector3i max = Arrays.stream(positions).reduce(new Vector3i(Integer.MIN_VALUE), Vector3i::max); + + BlockRegion region = BlockRegions.encompassing(positions); + assertEquals(min, region.getMin(new Vector3i()), "min of " + region); + assertEquals(max, region.getMax(new Vector3i()), "max of " + region); + assertEquals(expectedSize, region.getSize(new Vector3i()), "size of " + region); } @Test @@ -169,10 +193,58 @@ public void testCorrectBoundsFlip() { public void testCorrectBoundsMixed() { Vector3i min = new Vector3i(0, 0, 0); Vector3i max = new Vector3i(1, 1, 1); - BlockRegion region = BlockRegions.createFromMinAndMax(1,0,1, 0,1,0); + BlockRegion region = BlockRegions.createFromMinAndMax(1, 0, 1, 0, 1, 0); region.correctBounds(); assertEquals(min, region.getMin(new Vector3i())); assertEquals(max, region.getMax(new Vector3i())); } + + private static Stream testCenterArgs() { + return Stream.of( + Arguments.of( + new BlockRegion(), + new Vector3f(Float.NaN) + ), + // creating from min and max + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), + new Vector3f(0.5f, 0.5f, 0.5f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)), + new Vector3f(1f, 1f, 1f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(1, 1, 1)), + new Vector3f(0.5f, 0.5f, 0.5f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(2, 2, 2)), + new Vector3f(1.5f, 1.5f, 1.5f) + ), + // creating from center and extents + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)), + new Vector3f(0.5f, 0.5f, 0.5f) + ), + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0.5f, 0.5f, 0.5f), new Vector3f(0.5f, + 0.5f, 0.5f)), + new Vector3f(1f, 1f, 1f) + ), + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0.49f, 0.49f, 0.49f), new Vector3f(0.5f, + 0.5f, 0.5f)), + new Vector3f(.5f, .5f, .5f) + ) + + ); + } + + @ParameterizedTest + @MethodSource("testCenterArgs") + public void testCenter(BlockRegion region, Vector3fc expectedCenter) { + assertEquals(expectedCenter, region.center(new Vector3f())); + } } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegion.java b/engine/src/main/java/org/terasology/world/block/BlockRegion.java index 425980bd313..b5014b98634 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegion.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegion.java @@ -132,6 +132,16 @@ public int getMinZ() { return this.aabb.minZ; } + /** + * set source to current region + * @param source the source region + * @return this + */ + public BlockRegion set(BlockRegion source) { + this.aabb.set(source.aabb); + return this; + } + /** * Sets the minimum coordinate of the first block for this {@link BlockRegion} * @@ -436,12 +446,15 @@ public boolean containsBlock(Vector3ic pos) { } /** - * the center of the region + * The center of the region if the region is valid, {@link Float#NaN} in all dimensions otherwise. * * @param dest will hold the result * @return dest */ public Vector3f center(Vector3f dest) { + if (!this.isValid()) { + return dest.set(Float.NaN); + } return dest.set( aabb.minX + ((aabb.maxX - aabb.minX) / 2.0f), aabb.minY + ((aabb.maxY - aabb.minY) / 2.0f), diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegions.java b/engine/src/main/java/org/terasology/world/block/BlockRegions.java index be8703de3e2..c736b1123f9 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegions.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegions.java @@ -9,6 +9,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; +import java.util.Arrays; import java.util.Iterator; public final class BlockRegions { @@ -16,7 +17,13 @@ private BlockRegions() { } /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. + *

+ * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If + * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region + * will have a size of 0 along that dimension. + *

+ * Consider using {@link #encompassing(Vector3ic...)} as an alternative. * * @return new block region */ @@ -25,7 +32,13 @@ public static BlockRegion createFromMinAndMax(Vector3ic min, Vector3ic max) { } /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. + *

+ * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If + * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region + * will have a size of 0 along that dimension. + *

+ * Consider using {@link #encompassing(Vector3ic...)} as an alternative. * * @return new block region */ @@ -60,6 +73,16 @@ public static BlockRegion createFromCenterAndExtents(Vector3fc center, Vector3fc .setMax(new Vector3i(max, RoundingMode.FLOOR)); } + /** + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing all the given positions. + * + * @param positions the positions that must be contained in the resulting block region + * @return a new block region containing all given positions + */ + public static BlockRegion encompassing(Vector3ic... positions) { + return Arrays.stream(positions).reduce(new BlockRegion(), BlockRegion::union, BlockRegion::union); + } + /** * An iterable over the blocks in the block region, where each position is wrapped in a new {@link Vector3i}. *

diff --git a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java index c9e15c1effb..a619182a5df 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java @@ -16,6 +16,7 @@ package org.terasology.world.block.entity; import org.joml.Vector3f; +import org.joml.Vector3ic; import org.terasology.audio.AudioManager; import org.terasology.audio.StaticSound; import org.terasology.audio.events.PlaySoundEvent; @@ -30,6 +31,7 @@ import org.terasology.logic.inventory.events.DropItemEvent; import org.terasology.logic.inventory.events.GiveItemEvent; import org.terasology.logic.location.LocationComponent; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.physics.events.ImpulseEvent; import org.terasology.registry.In; @@ -39,6 +41,7 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegions; import org.terasology.world.block.entity.damage.BlockDamageModifierComponent; import org.terasology.world.block.items.BlockItemFactory; import org.terasology.world.block.items.OnBlockToItem; @@ -102,13 +105,13 @@ public void defaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, BlockRegionComponent blockRegion = entity.getComponent(BlockRegionComponent.class); if (blockComponent.dropBlocksInRegion) { // loop through all the blocks in this region and drop them - for (Vector3i location : blockRegion.region) { + for (Vector3ic location : BlockRegions.iterableInPlace(blockRegion.region)) { Block blockInWorld = worldProvider.getBlock(location); - commonDefaultDropsHandling(event, entity, location, blockInWorld.getBlockFamily().getArchetypeBlock()); + commonDefaultDropsHandling(event, entity, JomlUtil.from(location), blockInWorld.getBlockFamily().getArchetypeBlock()); } } else { // just drop the ActAsBlock block - Vector3i location = new Vector3i(blockRegion.region.center(), RoundingMode.HALF_UP); + Vector3i location = JomlUtil.from(new org.joml.Vector3i(blockRegion.region.center(new Vector3f()), org.joml.RoundingMode.HALF_UP)); commonDefaultDropsHandling(event, entity, location, blockComponent.block.getArchetypeBlock()); } } else if (entity.hasComponent(LocationComponent.class)) { diff --git a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java index 672efd394b4..7b3510fc122 100644 --- a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java +++ b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java @@ -4,20 +4,19 @@ package org.terasology.world.block.regions; import org.terasology.entitySystem.Component; -import org.terasology.math.Region3i; import org.terasology.network.Replicate; +import org.terasology.world.block.BlockRegion; /** */ public class BlockRegionComponent implements Component { @Replicate - public Region3i region = Region3i.empty(); - public boolean overrideBlockEntities = true; + public BlockRegion region = new BlockRegion(); public BlockRegionComponent() { } - public BlockRegionComponent(Region3i region) { - this.region = region; + public BlockRegionComponent(BlockRegion region) { + this.region.set(region); } } diff --git a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java index 44020048f0c..491b410c6eb 100644 --- a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java +++ b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.regions; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.EventPriority; import org.terasology.entitySystem.event.ReceiveEvent; @@ -9,10 +10,10 @@ import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.logic.health.DoDestroyEvent; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.In; import org.terasology.world.WorldProvider; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegions; /** */ @@ -28,7 +29,7 @@ public class BlockRegionSystem extends BaseComponentSystem { // trivial priority so that all other logic can happen to the region before erasing the blocks in the region @ReceiveEvent(priority = EventPriority.PRIORITY_TRIVIAL) public void onDestroyed(DoDestroyEvent event, EntityRef entity, BlockRegionComponent blockRegion) { - for (Vector3i blockPosition : blockRegion.region) { + for (Vector3ic blockPosition : BlockRegions.iterableInPlace(blockRegion.region)) { worldProvider.setBlock(blockPosition, blockManager.getBlock(BlockManager.AIR_ID)); } } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index e574030ea9f..b38c4f822d9 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -46,7 +46,6 @@ import org.terasology.logic.common.RetainComponentsComponent; import org.terasology.logic.location.LocationComponent; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; @@ -56,6 +55,8 @@ import org.terasology.world.OnChangedBlock; import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; import org.terasology.world.block.regions.BlockRegionComponent; import java.math.RoundingMode; @@ -78,8 +79,8 @@ public class EntityAwareWorldProvider extends AbstractWorldProviderDecorator imp // TODO: Or perhaps a build in indexing system for entities private Map blockEntityLookup = Maps.newHashMap(); - private Map blockRegionLookup = Maps.newHashMap(); - private Map blockRegions = Maps.newHashMap(); + private Map blockRegionLookup = Maps.newHashMap(); + private Map blockRegions = Maps.newHashMap(); private Set temporaryBlockEntities = Sets.newLinkedHashSet(); @@ -195,7 +196,7 @@ private void updateBlockEntity(EntityRef blockEntity, Vector3i pos, Block oldTyp } OnChangedBlock changedEvent = new OnChangedBlock(pos, type, oldType); - EntityRef regionEntity = blockRegionLookup.get(pos); + EntityRef regionEntity = blockRegionLookup.get(JomlUtil.from(pos)); if (regionEntity != null) { regionEntity.send(changedEvent); } @@ -409,7 +410,7 @@ public EntityRef getExistingEntityAt(Vector3i blockPosition) { @Override public EntityRef getExistingEntityAt(Vector3ic blockPosition) { if (GameThread.isCurrentThread()) { - EntityRef result = blockRegionLookup.get(JomlUtil.from(blockPosition)); + EntityRef result = blockRegionLookup.get((org.joml.Vector3i) blockPosition); if (result == null) { return getExistingBlockEntityAt(blockPosition); } @@ -474,28 +475,28 @@ public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) public void onBlockRegionActivated(OnActivatedComponent event, EntityRef entity) { BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (Vector3i pos : regionComp.region) { + for (org.joml.Vector3i pos : BlockRegions.iterable(regionComp.region)) { blockRegionLookup.put(pos, entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionChanged(OnChangedComponent event, EntityRef entity) { - Region3i oldRegion = blockRegions.get(entity); - for (Vector3i pos : oldRegion) { + BlockRegion oldRegion = blockRegions.get(entity); + for (org.joml.Vector3ic pos : BlockRegions.iterableInPlace(oldRegion)) { blockRegionLookup.remove(pos); } BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (Vector3i pos : regionComp.region) { + for (org.joml.Vector3i pos : BlockRegions.iterable(regionComp.region)) { blockRegionLookup.put(pos, entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionDeactivated(BeforeDeactivateComponent event, EntityRef entity) { - Region3i oldRegion = blockRegions.get(entity); - for (Vector3i pos : oldRegion) { + BlockRegion oldRegion = blockRegions.get(entity); + for (org.joml.Vector3ic pos : BlockRegions.iterableInPlace(oldRegion)) { blockRegionLookup.remove(pos); } blockRegions.remove(entity); @@ -514,6 +515,7 @@ private void cleanUpTemporaryEntity(EntityRef entity) { Prefab prefab = entity.getParentPrefab(); for (Component comp : entity.iterateComponents()) { + //TODO: should this also check for components listed in `RetainComponentsComponent`? if (!COMMON_BLOCK_COMPONENTS.contains(comp.getClass()) && (prefab == null || !prefab.hasComponent(comp.getClass()))) { entity.removeComponent(comp.getClass()); } From b332d0f0b749eaf6120dbdf222375a12fc17f9ed Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Wed, 9 Dec 2020 20:23:35 +0300 Subject: [PATCH 018/259] ci(subsystems): Make TypeHandlerLibrary publishable with engine's version (#4307) --- subsystems/TypeHandlerLibrary/build.gradle.kts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsystems/TypeHandlerLibrary/build.gradle.kts b/subsystems/TypeHandlerLibrary/build.gradle.kts index 75cc9c68452..ef7d9c56aaa 100644 --- a/subsystems/TypeHandlerLibrary/build.gradle.kts +++ b/subsystems/TypeHandlerLibrary/build.gradle.kts @@ -6,7 +6,10 @@ plugins { `java-library` } -apply(from = "$rootDir/config/gradle/common.gradle") +apply(from = "$rootDir/config/gradle/publish.gradle") + +group = "org.terasology.subsystems" +version = project(":engine").version dependencies { implementation("org.slf4j:slf4j-api:1.7.21") @@ -22,4 +25,4 @@ dependencies { testImplementation("org.mockito:mockito-junit-jupiter:3.2.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.5.2") -} \ No newline at end of file +} From 4bc7b53ca72b9c44dca28c28077d2ea325abb08d Mon Sep 17 00:00:00 2001 From: Asma <35783408+lasossette@users.noreply.github.com> Date: Thu, 10 Dec 2020 21:25:26 +0100 Subject: [PATCH 019/259] chore: removed count field for issue #4242 (#4308) Co-authored-by: asma --- .../org/terasology/logic/afk/AfkAuthoritySystem.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/afk/AfkAuthoritySystem.java b/engine/src/main/java/org/terasology/logic/afk/AfkAuthoritySystem.java index 09e0bd298ff..56acb79d27d 100644 --- a/engine/src/main/java/org/terasology/logic/afk/AfkAuthoritySystem.java +++ b/engine/src/main/java/org/terasology/logic/afk/AfkAuthoritySystem.java @@ -36,11 +36,9 @@ public class AfkAuthoritySystem extends BaseComponentSystem { @In private NetworkSystem networkSystem; - private int count; @ReceiveEvent public void onConnected(ConnectedEvent event, EntityRef entity) { - count++; if (!delayManager.hasPeriodicAction(entity, PERIODIC_ID)) { delayManager.addPeriodicAction(entity, PERIODIC_ID, 0, AFK_PERIOD); } @@ -48,13 +46,10 @@ public void onConnected(ConnectedEvent event, EntityRef entity) { @ReceiveEvent public void onDisconnected(DisconnectedEvent event, EntityRef entity) { - count--; if (delayManager.hasPeriodicAction(entity, PERIODIC_ID)) { delayManager.cancelPeriodicAction(entity, PERIODIC_ID); - if (count >= 1) { - for (Client player : networkSystem.getPlayers()) { - delayManager.addPeriodicAction(player.getEntity(), PERIODIC_ID, 0, AFK_PERIOD); - } + for (Client player : networkSystem.getPlayers()) { + delayManager.addPeriodicAction(player.getEntity(), PERIODIC_ID, 0, AFK_PERIOD); } } } From 244a7f7bec49a604e76264e2918ffdc692e5c827 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Thu, 10 Dec 2020 22:03:45 +0000 Subject: [PATCH 020/259] fix: don't delete camera during purgeWorld command (#4310) --- .../java/org/terasology/logic/players/CameraClientSystem.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java index 9867e2781af..eda977ef020 100644 --- a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java @@ -18,6 +18,7 @@ import org.terasology.entitySystem.entity.EntityBuilder; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.entitySystem.entity.internal.EntityScope; import org.terasology.entitySystem.entity.lifecycleEvents.OnActivatedComponent; import org.terasology.entitySystem.entity.lifecycleEvents.OnChangedComponent; import org.terasology.entitySystem.event.ReceiveEvent; @@ -81,6 +82,7 @@ private void ensureCameraEntityCreated() { EntityBuilder builder = entityManager.newBuilder("engine:camera"); builder.setPersistent(false); clientComponent.camera = builder.build(); + clientComponent.camera.setScope(EntityScope.GLOBAL); // Ensure that the camera isn't destroyed by the purgeWorld command. localPlayer.getClientEntity().saveComponent(clientComponent); } } From 00856a13aa3507284fd036c2c2b4f3b2a625a7fc Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Thu, 10 Dec 2020 22:30:24 +0000 Subject: [PATCH 021/259] chore: Remove all the remaining occurences of SurfaceHeightFacet (#4290) --- .../Zones/LayeredZoneRegionFunctionTest.java | 12 +++---- .../logic/spawner/AbstractSpawner.java | 12 +++---- .../ElevationCompatibilityProvider.java | 30 ---------------- .../SurfaceHeightCompatibilityProvider.java | 32 ----------------- .../generation/facets/ElevationFacet.java | 5 ++- .../generation/facets/SurfaceHeightFacet.java | 34 ------------------- .../generation/facets/SurfacesFacet.java | 5 ++- ...cetLayer.java => ElevationFacetLayer.java} | 14 ++++---- .../zones/LayeredZoneRegionFunction.java | 4 +-- 9 files changed, 23 insertions(+), 125 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/world/generation/ElevationCompatibilityProvider.java delete mode 100644 engine/src/main/java/org/terasology/world/generation/SurfaceHeightCompatibilityProvider.java delete mode 100644 engine/src/main/java/org/terasology/world/generation/facets/SurfaceHeightFacet.java rename engine/src/main/java/org/terasology/world/viewer/layers/engine/{SurfaceHeightFacetLayer.java => ElevationFacetLayer.java} (71%) diff --git a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java index c20da983c8a..a347eaa5784 100644 --- a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java @@ -27,7 +27,7 @@ import org.terasology.world.generation.Region; import org.terasology.world.generation.RegionImpl; import org.terasology.world.generation.WorldFacet; -import org.terasology.world.generation.facets.SurfaceHeightFacet; +import org.terasology.world.generation.facets.ElevationFacet; import org.terasology.world.zones.LayeredZoneRegionFunction; import org.terasology.world.zones.MinMaxLayerThickness; import org.terasology.world.zones.Zone; @@ -63,19 +63,19 @@ public void setup() { ListMultimap, FacetProvider> facetProviderChains = ArrayListMultimap.create(); - facetProviderChains.put(SurfaceHeightFacet.class, (generatingRegion) -> { - SurfaceHeightFacet facet = new SurfaceHeightFacet(generatingRegion.getRegion(), - generatingRegion.getBorderForFacet(SurfaceHeightFacet.class)); + facetProviderChains.put(ElevationFacet.class, (generatingRegion) -> { + ElevationFacet facet = new ElevationFacet(generatingRegion.getRegion(), + generatingRegion.getBorderForFacet(ElevationFacet.class)); for (BaseVector2i pos : facet.getRelativeRegion().contents()) { facet.set(pos, 100); } - generatingRegion.setRegionFacet(SurfaceHeightFacet.class, facet); + generatingRegion.setRegionFacet(ElevationFacet.class, facet); }); Map, Border3D> borders = new HashMap<>(); - borders.put(SurfaceHeightFacet.class, new Border3D(0, 0, 0)); + borders.put(ElevationFacet.class, new Border3D(0, 0, 0)); region = new RegionImpl(Region3i.createFromCenterExtents(new Vector3i(0, 0, 0), 4), facetProviderChains, borders); diff --git a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java index 83fe65912bd..e2e288cdab7 100644 --- a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java +++ b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java @@ -26,12 +26,11 @@ import org.terasology.math.TeraMath; import org.terasology.world.generation.Region; import org.terasology.world.generation.World; -import org.terasology.world.generation.facets.SurfacesFacet; import org.terasology.world.generation.facets.ElevationFacet; import org.terasology.world.generation.facets.SeaLevelFacet; import org.terasology.world.generation.facets.SpawnHeightFacet; import org.terasology.world.generation.facets.StrictlySparseSeaLevelFacet; -import org.terasology.world.generation.facets.SurfaceHeightFacet; +import org.terasology.world.generation.facets.SurfacesFacet; import java.util.Optional; import java.util.function.Function; @@ -39,12 +38,12 @@ public abstract class AbstractSpawner implements Spawner { /** - * Tries to find a suitable spawning point based on {@link SurfaceHeightFacet} and {@link SeaLevelFacet}. + * Tries to find a suitable spawning point based on {@link SurfacesFacet} and {@link ElevationFacet}. * @param searchRadius the radius within a suitable spawning point will be searched * @param world the facet-based world * @param pos the desired 2D position in that world * @return a 3D position above the surface and sea level or null if none was found - * @throws IllegalStateException if no SurfaceHeightFacet can be created. + * @throws IllegalStateException if no required facets can be created. */ protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius) { @@ -60,7 +59,6 @@ protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius // check if generation uses sea level and surface height facets SurfacesFacet surfacesFacet = worldRegion.getFacet(SurfacesFacet.class); ElevationFacet elevationFacet = worldRegion.getFacet(ElevationFacet.class); - SurfaceHeightFacet surfaceHeightFacet = worldRegion.getFacet(SurfaceHeightFacet.class); SpawnHeightFacet spawnHeightFacet = worldRegion.getFacet(SpawnHeightFacet.class); if (spawnHeightFacet != null) { @@ -71,10 +69,8 @@ protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius } else { getWorld = v -> Optional.of(elevationFacet.getWorld(v.x(), v.y())); } - } else if (surfaceHeightFacet != null) { - getWorld = v -> Optional.of(surfaceHeightFacet.getWorld(v.x(), v.y())); } else { - throw new IllegalStateException("No spawn height facet, elevation facet or surface height facet found. Can't place spawn point."); + throw new IllegalStateException("No spawn height facet or elevation facet facet found. Can't place spawn point."); } Function> getSeaLevel; diff --git a/engine/src/main/java/org/terasology/world/generation/ElevationCompatibilityProvider.java b/engine/src/main/java/org/terasology/world/generation/ElevationCompatibilityProvider.java deleted file mode 100644 index 2a1269ac29b..00000000000 --- a/engine/src/main/java/org/terasology/world/generation/ElevationCompatibilityProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.world.generation; - -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Rect2i; -import org.terasology.world.generation.facets.DensityFacet; -import org.terasology.world.generation.facets.ElevationFacet; -import org.terasology.world.generation.facets.SurfaceHeightFacet; - -/** - * Converts from {@link SurfaceHeightFacet} to {@link ElevationFacet}, - * to be used for backwards compatibility while transitioning away from {@link SurfaceHeightFacet}. - */ -@Produces(ElevationFacet.class) -@Requires(@Facet(SurfaceHeightFacet.class)) -public class ElevationCompatibilityProvider implements FacetProvider { - @Override - public void process(GeneratingRegion region) { - SurfaceHeightFacet surfaceHeight = region.getRegionFacet(SurfaceHeightFacet.class); - ElevationFacet facet = new ElevationFacet(region.getRegion(), region.getBorderForFacet(ElevationFacet.class)); - - for (BaseVector2i pos : facet.getRelativeRegion().contents()) { - facet.set(pos, surfaceHeight.get(pos)); - } - region.setRegionFacet(ElevationFacet.class, facet); - } -} diff --git a/engine/src/main/java/org/terasology/world/generation/SurfaceHeightCompatibilityProvider.java b/engine/src/main/java/org/terasology/world/generation/SurfaceHeightCompatibilityProvider.java deleted file mode 100644 index 5adc035fa06..00000000000 --- a/engine/src/main/java/org/terasology/world/generation/SurfaceHeightCompatibilityProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.world.generation; - -import org.terasology.math.geom.BaseVector2i; -import org.terasology.world.generation.facets.SurfacesFacet; -import org.terasology.world.generation.facets.ElevationFacet; -import org.terasology.world.generation.facets.SurfaceHeightFacet; - -/** - * Converts from {@link ElevationFacet} and {@link SurfacesFacet} to {@link SurfaceHeightFacet}, - * to be used for backwards compatibility while transitioning away from {@link SurfaceHeightFacet}. - * - * The output heights may in some cases depend on the vertical extent of the - * generating region, but usually not in a way that substantially affects generation. - */ -@Produces(SurfaceHeightFacet.class) -@Requires({@Facet(ElevationFacet.class), @Facet(SurfacesFacet.class)}) -public class SurfaceHeightCompatibilityProvider implements FacetProvider { - @Override - public void process(GeneratingRegion region) { - SurfacesFacet surfacesFacet = region.getRegionFacet(SurfacesFacet.class); - ElevationFacet elevationFacet = region.getRegionFacet(ElevationFacet.class); - SurfaceHeightFacet facet = new SurfaceHeightFacet(region.getRegion(), region.getBorderForFacet(SurfaceHeightFacet.class)); - - for (BaseVector2i pos : facet.getWorldRegion().contents()) { - facet.setWorld(pos, surfacesFacet.getPrimarySurface(elevationFacet, pos.x(), pos.y()).orElse(elevationFacet.getWorld(pos))); - } - region.setRegionFacet(SurfaceHeightFacet.class, facet); - } -} diff --git a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java index d4b2eb0f567..45d082ef787 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java @@ -11,9 +11,8 @@ * This facet represents the approximate height of the conceptual surface of the ground at each position. * It may exclude local features such as caves. It is intended to be used to determine the altitude relative * to the ground of features that are not placed directly on the surface, such as placing ores at a certain - * depth below ground. - * - * The combination of the {@link SurfacesFacet} and the ElevationFacet is a more flexible alternative to the {@link SurfaceHeightFacet}. + * depth below ground. Things that require more precise details of where all the surfaces are should use the + * {@link SurfacesFacet} instead. */ public class ElevationFacet extends BaseFieldFacet2D { diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHeightFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHeightFacet.java deleted file mode 100644 index 3769997fe2c..00000000000 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHeightFacet.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.world.generation.facets; - -import org.terasology.math.Region3i; -import org.terasology.world.generation.Border3D; -import org.terasology.world.generation.facets.base.BaseFieldFacet2D; - -/** - * This facet represents the height of the ground at each point. - * - * @deprecated in favour of the {@link SurfacesFacet} and the {@link ElevationFacet}, which - * each cover different parts of this facet's purpose, and are a more flexible alternative. - */ -@Deprecated -public class SurfaceHeightFacet extends BaseFieldFacet2D { - - public SurfaceHeightFacet(Region3i targetRegion, Border3D border) { - super(targetRegion, border); - } -} diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java index 363c4586089..3d10a41ef26 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java @@ -13,9 +13,8 @@ /** * This facet represents the heights of all of the surfaces of the ground. There may be multiple surfaces * in one column, for example, where there are overhangs, or floating islands. This facet is intended to - * be used for placement of features on the surface itself, such as grass, trees and buildings. - * - * The combination of the SurfacesFacet and the {@link ElevationFacet} is a more flexible alternative to the {@link SurfaceHeightFacet}. + * be used for placement of features on the surface itself, such as grass, trees and buildings. Things that + * require a single altitude value should use the {@link ElevationFacet} instead. */ public class SurfacesFacet extends VerticallySparseBooleanFacet3D { diff --git a/engine/src/main/java/org/terasology/world/viewer/layers/engine/SurfaceHeightFacetLayer.java b/engine/src/main/java/org/terasology/world/viewer/layers/engine/ElevationFacetLayer.java similarity index 71% rename from engine/src/main/java/org/terasology/world/viewer/layers/engine/SurfaceHeightFacetLayer.java rename to engine/src/main/java/org/terasology/world/viewer/layers/engine/ElevationFacetLayer.java index f1621c99ee1..38d0b96f0b5 100644 --- a/engine/src/main/java/org/terasology/world/viewer/layers/engine/SurfaceHeightFacetLayer.java +++ b/engine/src/main/java/org/terasology/world/viewer/layers/engine/ElevationFacetLayer.java @@ -16,7 +16,7 @@ package org.terasology.world.viewer.layers.engine; -import org.terasology.world.generation.facets.SurfaceHeightFacet; +import org.terasology.world.generation.facets.ElevationFacet; import org.terasology.world.viewer.layers.FieldFacetLayer; import org.terasology.world.viewer.layers.Renders; import org.terasology.world.viewer.layers.ZOrder; @@ -24,18 +24,18 @@ /** * Provides information about the surface height level. */ -@Renders(value = SurfaceHeightFacet.class, order = ZOrder.SURFACE) -public class SurfaceHeightFacetLayer extends FieldFacetLayer { +@Renders(value = ElevationFacet.class, order = ZOrder.SURFACE) +public class ElevationFacetLayer extends FieldFacetLayer { /** * This is called through reflection. * @param config the configuration params */ - public SurfaceHeightFacetLayer(Config config) { - super(SurfaceHeightFacet.class, config); + public ElevationFacetLayer(Config config) { + super(ElevationFacet.class, config); } - public SurfaceHeightFacetLayer() { - super(SurfaceHeightFacet.class, 0d, 1.0d); + public ElevationFacetLayer() { + super(ElevationFacet.class, 0d, 1.0d); } } diff --git a/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java b/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java index a15213f73e3..0f860ad7a2d 100644 --- a/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java +++ b/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java @@ -19,7 +19,7 @@ import org.terasology.module.sandbox.API; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.generation.Region; -import org.terasology.world.generation.facets.SurfaceHeightFacet; +import org.terasology.world.generation.facets.ElevationFacet; import java.util.Comparator; import java.util.List; @@ -93,7 +93,7 @@ public void initialize(Zone parent) { private LayerRange getLayerRange(int x, int z, Region region) { Vector2i pos = new Vector2i(x, z); if (!layerRangeMap.containsKey(pos)) { - int surfaceHeight = (int) Math.floor(region.getFacet(SurfaceHeightFacet.class).getWorld(pos)); + int surfaceHeight = (int) Math.floor(region.getFacet(ElevationFacet.class).getWorld(pos)); boolean aboveground = ordering > 0; int cumulativeDistanceSmall = 0; From e4d9a62c4aafc866b0f2bf92955b5943e7861263 Mon Sep 17 00:00:00 2001 From: jdrueckert Date: Sat, 12 Dec 2020 20:25:08 +0100 Subject: [PATCH 022/259] feat(JOML): migrate `character` package events and systems (#4279) --- .../characters/CharacterImpulseEvent.java | 2 +- .../CharacterMovementSystemUtility.java | 20 ++++---- .../characters/CharacterSoundSystem.java | 2 +- .../logic/characters/CharacterStateEvent.java | 12 ++--- .../ClientCharacterPredictionSystem.java | 8 ++-- .../characters/KinematicCharacterMover.java | 48 +++++++++---------- .../ServerCharacterPredictionSystem.java | 9 ++-- .../characters/events/CollisionEvent.java | 2 +- .../events/HorizontalCollisionEvent.java | 2 +- .../events/VerticalCollisionEvent.java | 2 +- .../logic/debug/MovementDebugCommands.java | 2 +- .../terasology/physics/events/MovedEvent.java | 12 ++--- .../CharacterStateEventPositionMap.java | 5 +- 13 files changed, 64 insertions(+), 62 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java index b576d54d6ee..7ce04042114 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java @@ -16,7 +16,7 @@ package org.terasology.logic.characters; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; public class CharacterImpulseEvent implements Event { Vector3f direction; diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java b/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java index cb1477cad03..64e96f72019 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java @@ -37,7 +37,7 @@ public void setToState(EntityRef entity, CharacterStateEvent state) { LocationComponent location = entity.getComponent(LocationComponent.class); CharacterMovementComponent movementComp = entity.getComponent(CharacterMovementComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x) || movementComp == null) { + if (location == null || !location.getWorldPosition(new Vector3f()).isFinite() || movementComp == null) { return; } location.setWorldPosition(state.getPosition()); @@ -45,12 +45,12 @@ public void setToState(EntityRef entity, CharacterStateEvent state) { entity.saveComponent(location); movementComp.mode = state.getMode(); - movementComp.setVelocity(JomlUtil.from(state.getVelocity())); + movementComp.setVelocity(state.getVelocity()); movementComp.grounded = state.isGrounded(); movementComp.footstepDelta = state.getFootstepDelta(); entity.saveComponent(movementComp); - setPhysicsLocation(entity, JomlUtil.from(state.getPosition())); + setPhysicsLocation(entity, state.getPosition()); // set the pitch to the character's gaze entity Quaternionf rotation = new Quaternionf().rotationX(TeraMath.DEG_TO_RAD * state.getPitch()); @@ -66,9 +66,9 @@ public void setToState(EntityRef entity, CharacterStateEvent state) { public void setToInterpolateState(EntityRef entity, CharacterStateEvent a, CharacterStateEvent b, long time) { float t = (float) (time - a.getTime()) / (b.getTime() - a.getTime()); - Vector3f newPos = JomlUtil.from(a.getPosition()).lerp(JomlUtil.from(b.getPosition()),t); - Quaternionf newRot = JomlUtil.from(a.getRotation()).nlerp(JomlUtil.from(b.getRotation()),t); - + Vector3f newPos = a.getPosition().lerp(b.getPosition(),t); + Quaternionf newRot = a.getRotation().nlerp(b.getRotation(),t); + entity.updateComponent(LocationComponent.class, location -> { location.setWorldPosition(JomlUtil.from(newPos)); location.setWorldRotation(JomlUtil.from(newRot)); @@ -77,7 +77,7 @@ public void setToInterpolateState(EntityRef entity, CharacterStateEvent a, Chara entity.updateComponent(CharacterMovementComponent.class, movementComponent -> { movementComponent.mode = a.getMode(); - movementComponent.setVelocity(JomlUtil.from(a.getVelocity())); + movementComponent.setVelocity(a.getVelocity()); movementComponent.grounded = a.isGrounded(); if (b.getFootstepDelta() < a.getFootstepDelta()) { movementComponent.footstepDelta = t * (1 + b.getFootstepDelta() - a.getFootstepDelta()) + a.getFootstepDelta(); @@ -99,9 +99,9 @@ public void setToInterpolateState(EntityRef entity, CharacterStateEvent a, Chara public void setToExtrapolateState(EntityRef entity, CharacterStateEvent state, long time) { float t = (time - state.getTime()) * 0.0001f; - Vector3f newPos = new Vector3f(JomlUtil.from(state.getVelocity())); + Vector3f newPos = new Vector3f(state.getVelocity()); newPos.mul(t); - newPos.add(JomlUtil.from(state.getPosition())); + newPos.add(state.getPosition()); extrapolateLocationComponent(entity, state, newPos); extrapolateCharacterMovementComponent(entity, state); @@ -119,7 +119,7 @@ private void extrapolateLocationComponent(EntityRef entity, CharacterStateEvent private void extrapolateCharacterMovementComponent(EntityRef entity, CharacterStateEvent state) { CharacterMovementComponent movementComponent = entity.getComponent(CharacterMovementComponent.class); movementComponent.mode = state.getMode(); - movementComponent.setVelocity(JomlUtil.from(state.getVelocity())); + movementComponent.setVelocity(state.getVelocity()); movementComponent.grounded = state.isGrounded(); entity.saveComponent(movementComponent); } diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java b/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java index ebac1c40137..0566bfc8c41 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java @@ -109,7 +109,7 @@ public void onJump(JumpEvent event, EntityRef entity, CharacterSoundComponent ch @ReceiveEvent public void onLanded(VerticalCollisionEvent event, EntityRef entity, CharacterSoundComponent characterSounds) { - Vector3f velocity = JomlUtil.from(event.getVelocity()); + Vector3f velocity = event.getVelocity(); float soundVolumeModifier = (velocity.y * -1 - LANDING_VELOCITY_THRESHOLD) * LANDING_VOLUME_MODIFIER; if (soundVolumeModifier <= 0f) { diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java index f61199df6d4..81cb01139bd 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java @@ -16,9 +16,9 @@ package org.terasology.logic.characters; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.terasology.network.BroadcastEvent; import org.terasology.network.NetworkEvent; @@ -27,7 +27,7 @@ public class CharacterStateEvent extends NetworkEvent { private long time; private int sequenceNumber; private Vector3f position = new Vector3f(); - private Quat4f rotation = new Quat4f(0, 0, 0, 1); + private Quaternionf rotation = new Quaternionf(0, 0, 0, 1); private MovementMode mode = MovementMode.WALKING; private boolean grounded; private Vector3f velocity = new Vector3f(); @@ -57,7 +57,7 @@ public CharacterStateEvent( long time, int sequenceNumber, Vector3f position, - Quat4f rotation, + Quaternionf rotation, Vector3f velocity, float yaw, float pitch, @@ -82,7 +82,7 @@ public Vector3f getPosition() { return position; } - public Quat4f getRotation() { + public Quaternionf getRotation() { return rotation; } diff --git a/engine/src/main/java/org/terasology/logic/characters/ClientCharacterPredictionSystem.java b/engine/src/main/java/org/terasology/logic/characters/ClientCharacterPredictionSystem.java index bb8729efb87..32df2feb825 100644 --- a/engine/src/main/java/org/terasology/logic/characters/ClientCharacterPredictionSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/ClientCharacterPredictionSystem.java @@ -18,7 +18,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Queues; - +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.Time; @@ -27,15 +28,14 @@ import org.terasology.entitySystem.entity.lifecycleEvents.OnActivatedComponent; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; -import org.terasology.registry.In; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.UpdateSubscriberSystem; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.geom.Vector3f; import org.terasology.network.ClientComponent; import org.terasology.physics.engine.PhysicsEngine; +import org.terasology.registry.In; import org.terasology.utilities.collection.CircularBuffer; import org.terasology.world.WorldProvider; @@ -140,7 +140,7 @@ public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { private CharacterStateEvent createInitialState(EntityRef entity) { LocationComponent location = entity.getComponent(LocationComponent.class); - return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(), location.getWorldRotation(), new Vector3f(), 0, 0, MovementMode.WALKING, false); + return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(new org.joml.Vector3f()), location.getWorldRotation(new Quaternionf()), new Vector3f(), 0, 0, MovementMode.WALKING, false); } private CharacterStateEvent stepState(CharacterMoveInputEvent input, CharacterStateEvent lastState, EntityRef entity) { diff --git a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java index 233c8c385e9..950144572b4 100644 --- a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java +++ b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java @@ -106,8 +106,8 @@ public CharacterStateEvent step(CharacterStateEvent initial, CharacterMoveInputE // The CharacterMovementComponent also has a 'radius' which may be used here. // Question: Is this connected with _shapes_ or bounding boxes in some way? checkBlockEntry(entity, - new Vector3i(JomlUtil.from(initial.getPosition()), org.joml.RoundingMode.HALF_UP), - new Vector3i(JomlUtil.from(result.getPosition()), org.joml.RoundingMode.HALF_UP), + new Vector3i(initial.getPosition(), org.joml.RoundingMode.HALF_UP), + new Vector3i(result.getPosition(), org.joml.RoundingMode.HALF_UP), characterMovementComponent.height); } if (result.getMode() != MovementMode.GHOSTING && result.getMode() != MovementMode.NONE) { @@ -175,7 +175,7 @@ private void checkMode(final CharacterMovementComponent movementComp, final Char if (!state.getMode().respondToEnvironment) { return; } - Vector3f worldPos = JomlUtil.from(state.getPosition()); + Vector3f worldPos = state.getPosition(); Vector3f top = new Vector3f(worldPos); Vector3f bottom = new Vector3f(worldPos); top.y += 0.5f * movementComp.height; @@ -193,7 +193,7 @@ private void checkMode(final CharacterMovementComponent movementComp, final Char finalDir = findClimbable(movementComp, worldPos, newSwimming, newDiving); if (finalDir != null) { newClimbing = true; - state.setClimbDirection(JomlUtil.from(finalDir)); + state.setClimbDirection(finalDir); } } @@ -338,10 +338,10 @@ private Vector3f extractResidualMovement(Vector3f hitNormal, Vector3f direction, private void followToParent(final CharacterStateEvent state, EntityRef entity) { LocationComponent locationComponent = entity.getComponent(LocationComponent.class); if (!locationComponent.getParent().equals(EntityRef.NULL)) { - Vector3f velocity = new Vector3f(JomlUtil.from(locationComponent.getWorldPosition())); - velocity.sub(JomlUtil.from(state.getPosition())); - state.getVelocity().set(JomlUtil.from(velocity)); - state.getPosition().set(locationComponent.getWorldPosition()); + Vector3f velocity = new Vector3f(locationComponent.getWorldPosition(new Vector3f())); + velocity.sub(state.getPosition()); + state.getVelocity().set(velocity); + state.getPosition().set(locationComponent.getWorldPosition(new Vector3f())); } } @@ -576,9 +576,9 @@ private void updateRotation(CharacterMovementComponent movementComp, CharacterSt CharacterMoveInputEvent input) { if (movementComp.faceMovementDirection && result.getVelocity().lengthSquared() > 0.01f) { float yaw = (float) Math.atan2(result.getVelocity().x, result.getVelocity().z); - result.getRotation().set(JomlUtil.from(new Vector3f(0, 1, 0)), yaw); + result.getRotation().set(0, 1, 0, yaw); } else { - result.getRotation().set(new Quat4f(TeraMath.DEG_TO_RAD * input.getYaw(), 0, 0)); + result.getRotation().set(new Quaternionf().rotationYXZ(org.joml.Math.toRadians(input.getYaw()), 0, 0)); } } @@ -622,9 +622,9 @@ private void walk(final CharacterMovementComponent movementComp, final Character // Modify velocity towards desired, up to the maximum rate determined by friction Vector3f velocityDiff = new Vector3f(desiredVelocity); - velocityDiff.sub(JomlUtil.from(state.getVelocity())); + velocityDiff.sub(state.getVelocity()); velocityDiff.mul(Math.min(movementComp.mode.scaleInertia * input.getDelta(), 1.0f)); - Vector3f endVelocity = new Vector3f(JomlUtil.from(state.getVelocity())); + Vector3f endVelocity = new Vector3f(state.getVelocity()); endVelocity.x += velocityDiff.x; endVelocity.z += velocityDiff.z; if (movementComp.mode.scaleGravity == 0) { @@ -638,14 +638,14 @@ private void walk(final CharacterMovementComponent movementComp, final Character Vector3f moveDelta = new Vector3f(endVelocity); moveDelta.mul(input.getDelta()); CharacterCollider collider = movementComp.mode.useCollision ? physics.getCharacterCollider(entity) : null; - MoveResult moveResult = move(JomlUtil.from(state.getPosition()), moveDelta, + MoveResult moveResult = move(state.getPosition(), moveDelta, (state.getMode() != MovementMode.CLIMBING && state.isGrounded() && movementComp.mode.canBeGrounded) ? movementComp.stepHeight : 0, movementComp.slopeFactor, collider); Vector3f distanceMoved = new Vector3f(moveResult.getFinalPosition()); - distanceMoved.sub(JomlUtil.from(state.getPosition())); - state.getPosition().set(JomlUtil.from(moveResult.getFinalPosition())); + distanceMoved.sub(state.getPosition()); + state.getPosition().set(moveResult.getFinalPosition()); if (input.isFirstRun() && distanceMoved.length() > 0) { - entity.send(new MovedEvent(new ImmutableVector3f(JomlUtil.from(distanceMoved)), new ImmutableVector3f(state.getPosition()))); + entity.send(new MovedEvent(new Vector3f(distanceMoved), new Vector3f(state.getPosition()))); } // Upon hitting solid ground, reset the number of jumps back to the maximum value. @@ -656,9 +656,9 @@ private void walk(final CharacterMovementComponent movementComp, final Character if (moveResult.isBottomHit()) { if (!state.isGrounded() && movementComp.mode.canBeGrounded) { if (input.isFirstRun()) { - Vector3f landVelocity = new Vector3f(JomlUtil.from(state.getVelocity())); + Vector3f landVelocity = new Vector3f(state.getVelocity()); landVelocity.y += (distanceMoved.y / moveDelta.y) * (endVelocity.y - state.getVelocity().y); - entity.send(new VerticalCollisionEvent(state.getPosition(), JomlUtil.from(landVelocity))); + entity.send(new VerticalCollisionEvent(state.getPosition(), landVelocity)); } state.setGrounded(true); movementComp.numberOfJumpsLeft = movementComp.numberOfJumpsMax; @@ -688,9 +688,9 @@ private void walk(final CharacterMovementComponent movementComp, final Character } else { if (moveResult.isTopHit() && endVelocity.y > 0) { if (input.isFirstRun()) { - Vector3f hitVelocity = new Vector3f(JomlUtil.from(state.getVelocity())); + Vector3f hitVelocity = new Vector3f(state.getVelocity()); hitVelocity.y += (distanceMoved.y / moveDelta.y) * (endVelocity.y - state.getVelocity().y); - entity.send(new VerticalCollisionEvent(state.getPosition(), JomlUtil.from(hitVelocity))); + entity.send(new VerticalCollisionEvent(state.getPosition(), hitVelocity)); } endVelocity.y = -0.0f * endVelocity.y; } @@ -721,12 +721,12 @@ private void walk(final CharacterMovementComponent movementComp, final Character } } if (input.isFirstRun() && moveResult.isHorizontalHit()) { - Vector3f hitVelocity = new Vector3f(JomlUtil.from(state.getVelocity())); + Vector3f hitVelocity = new Vector3f(state.getVelocity()); hitVelocity.x += (distanceMoved.x / moveDelta.x) * (endVelocity.x - state.getVelocity().x); hitVelocity.z += (distanceMoved.z / moveDelta.z) * (endVelocity.z - state.getVelocity().z); - entity.send(new HorizontalCollisionEvent(state.getPosition(), JomlUtil.from(hitVelocity))); + entity.send(new HorizontalCollisionEvent(state.getPosition(), hitVelocity)); } - state.getVelocity().set(JomlUtil.from(endVelocity)); + state.getVelocity().set(endVelocity); if (state.isGrounded() || movementComp.mode == MovementMode.SWIMMING || movementComp.mode == MovementMode.DIVING) { state.setFootstepDelta( state.getFootstepDelta() + distanceMoved.length() / movementComp.distanceBetweenFootsteps); @@ -759,7 +759,7 @@ private void climb(final CharacterStateEvent state, CharacterMoveInputEvent inpu } Vector3f tmp; - Vector3i climbDir3i = JomlUtil.from(state.getClimbDirection()); + Vector3i climbDir3i = state.getClimbDirection(); Vector3f climbDir3f = new Vector3f(climbDir3i); Quaternionf rotation = new Quaternionf().rotationYXZ(TeraMath.DEG_TO_RAD * state.getYaw(), 0, 0); diff --git a/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java b/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java index 684f12442af..abba55a1284 100644 --- a/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java @@ -19,6 +19,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.joml.Quaternionf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.Time; @@ -34,7 +35,7 @@ import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; import org.terasology.network.NetworkSystem; import org.terasology.physics.engine.CharacterCollider; import org.terasology.physics.engine.PhysicsEngine; @@ -147,7 +148,7 @@ public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) { characterStateEventPositionMap.updateCharacterStateEvent(newState); } else if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.RECORDING) { - characterStateEventPositionMap.add(newState.getSequenceNumber(), newState.getPosition(), newState.getVelocity()); + characterStateEventPositionMap.add(newState.getSequenceNumber(), JomlUtil.from(newState.getPosition()), JomlUtil.from(newState.getVelocity())); } characterMovementSystemUtility.setToState(entity, newState); @@ -162,7 +163,7 @@ public void onTeleport(CharacterTeleportEvent event, EntityRef entity) { CircularBuffer stateBuffer = characterStates.get(entity); CharacterStateEvent lastState = stateBuffer.getLast(); CharacterStateEvent newState = new CharacterStateEvent(lastState); - newState.setPosition(new Vector3f(JomlUtil.from(event.getTargetPosition()))); + newState.setPosition(new Vector3f(event.getTargetPosition())); newState.setTime(time.getGameTimeInMs()); stateBuffer.add(newState); characterMovementSystemUtility.setToState(entity, newState); @@ -185,7 +186,7 @@ public void onImpulse(CharacterImpulseEvent event, EntityRef entity) { private CharacterStateEvent createInitialState(EntityRef entity) { LocationComponent location = entity.getComponent(LocationComponent.class); - return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(), location.getWorldRotation(), new Vector3f(), 0, 0, MovementMode.WALKING, false); + return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(new Vector3f()), location.getWorldRotation(new Quaternionf()), new Vector3f(), 0, 0, MovementMode.WALKING, false); } private CharacterStateEvent stepState(CharacterMoveInputEvent input, CharacterStateEvent lastState, EntityRef entity) { diff --git a/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java index ce9a37de8cd..ac6e8443d1a 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java @@ -16,7 +16,7 @@ package org.terasology.logic.characters.events; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; /** */ diff --git a/engine/src/main/java/org/terasology/logic/characters/events/HorizontalCollisionEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/HorizontalCollisionEvent.java index 26ba383afd9..1bbb3e2d63c 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/HorizontalCollisionEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/HorizontalCollisionEvent.java @@ -15,7 +15,7 @@ */ package org.terasology.logic.characters.events; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; /** */ diff --git a/engine/src/main/java/org/terasology/logic/characters/events/VerticalCollisionEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/VerticalCollisionEvent.java index 40599256ed9..8bdc625e9ad 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/VerticalCollisionEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/VerticalCollisionEvent.java @@ -15,7 +15,7 @@ */ package org.terasology.logic.characters.events; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; /** */ diff --git a/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java b/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java index b9fc736e157..83e3d702afe 100644 --- a/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java +++ b/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java @@ -102,7 +102,7 @@ public String setSpeedMultiplier(@Sender EntityRef client, @CommandParam("amount public String pushCharacterCommand(@Sender EntityRef sender, @CommandParam("x") float x, @CommandParam("y") float y, @CommandParam("z") float z) { ClientComponent clientComponent = sender.getComponent(ClientComponent.class); - clientComponent.character.send(new CharacterImpulseEvent(JomlUtil.from(new Vector3f(x, y, z)))); + clientComponent.character.send(new CharacterImpulseEvent(new Vector3f(x, y, z))); return "Pushing character with " + x + " " + y + " " + z; } diff --git a/engine/src/main/java/org/terasology/physics/events/MovedEvent.java b/engine/src/main/java/org/terasology/physics/events/MovedEvent.java index 9744f6f535a..b4da9fe825e 100644 --- a/engine/src/main/java/org/terasology/physics/events/MovedEvent.java +++ b/engine/src/main/java/org/terasology/physics/events/MovedEvent.java @@ -17,22 +17,22 @@ package org.terasology.physics.events; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.BaseVector3f; +import org.joml.Vector3fc; public class MovedEvent implements Event { - private BaseVector3f delta; - private BaseVector3f finalPosition; + private Vector3fc delta; + private Vector3fc finalPosition; - public MovedEvent(BaseVector3f delta, BaseVector3f finalPosition) { + public MovedEvent(Vector3fc delta, Vector3fc finalPosition) { this.delta = delta; this.finalPosition = finalPosition; } - public BaseVector3f getDelta() { + public Vector3fc getDelta() { return delta; } - public BaseVector3f getPosition() { + public Vector3fc getPosition() { return finalPosition; } } diff --git a/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java b/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java index f6a5d250e6e..8542a763106 100644 --- a/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java +++ b/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java @@ -16,6 +16,7 @@ package org.terasology.recording; import org.terasology.logic.characters.CharacterStateEvent; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3f; import java.util.HashMap; @@ -70,7 +71,7 @@ public void reset() { */ public void updateCharacterStateEvent(CharacterStateEvent event) { Vector3f[] data = this.idToData.get(event.getSequenceNumber()); - event.setPosition(data[0]); - event.setVelocity(data[1]); + event.setPosition(JomlUtil.from(data[0])); + event.setVelocity(JomlUtil.from(data[1])); } } From b469d1683a5e687190a88df80f30154b3be7202f Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 12 Dec 2020 11:33:24 -0800 Subject: [PATCH 023/259] chore (idea): gitignore discord plugin --- .idea/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.idea/.gitignore b/.idea/.gitignore index a1bdffed616..063180a3c14 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -32,5 +32,8 @@ workspace.xml # Ignore Sonar linting, if set up locally /sonarlint/ +# Discord preferences don't need sharing +/discord.xml + # Automatically created when the checkout directy name is different from git origin? /.name From 1875f3f512521d2ee3e9c8996b30b4922e3fd88c Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 14 Nov 2020 17:00:36 -0800 Subject: [PATCH 024/259] chore (git): ignore .idea/caches --- .idea/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.idea/.gitignore b/.idea/.gitignore index 063180a3c14..54bad757e64 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -5,6 +5,8 @@ workspace.xml *.iws +/caches + # Shelf is where it put changes you're not ready to share. (it's like git stash) /shelf From 3044dc10252ca557308dab9f076fdc467207331e Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 12 Dec 2020 11:42:13 -0800 Subject: [PATCH 025/259] chore (idea): gitignore codestream plugin It's plausible we might want to share a teamId? But the webViewContext looks like user-specific local state. --- .idea/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.idea/.gitignore b/.idea/.gitignore index 54bad757e64..6f1ee0cc2b2 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -37,5 +37,8 @@ workspace.xml # Discord preferences don't need sharing /discord.xml +# CodeStream's webViewContext looks like local state +/codestream.xml + # Automatically created when the checkout directy name is different from git origin? /.name From 7ee3e26824897ea12c3f8dc07641a5daf647fc67 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 12 Dec 2020 13:26:45 -0800 Subject: [PATCH 026/259] chore(joml): add toBlockMapping utility (#4314) --- engine/src/main/java/org/terasology/math/JomlUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engine/src/main/java/org/terasology/math/JomlUtil.java b/engine/src/main/java/org/terasology/math/JomlUtil.java index 01180930c39..3be42d095e2 100644 --- a/engine/src/main/java/org/terasology/math/JomlUtil.java +++ b/engine/src/main/java/org/terasology/math/JomlUtil.java @@ -42,8 +42,12 @@ import org.terasology.math.geom.Rect2f; import org.terasology.math.geom.Rect2i; import org.terasology.math.geom.Vector3f; +import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import java.util.Map; +import java.util.stream.Collectors; + public final class JomlUtil { private JomlUtil() { @@ -237,4 +241,8 @@ public static Rectanglei rectangleiFromMinAndSize(int minX, int minY, int width, public static Rectanglef rectanglefFromMinAndSize(float minX, float minY, float width, float height) { return new Rectanglef(minX, minY, minX + width, minY + height); } + + public static Map blockMap(Map maps) { + return maps.entrySet().stream().collect(Collectors.toMap(k -> JomlUtil.from(k.getKey()), Map.Entry::getValue)); + } } From 094417fbf8da122cfaad7cc986a54edfb432a559 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 12 Dec 2020 15:16:29 -0800 Subject: [PATCH 027/259] remove Transfrom from MeshRenderer (#4261) * remove Transfrom from MeshRenderer * clean up location logic * add javadocs for deprecated method Co-authored-by: jdrueckert --- .../bullet/shapes/BulletCompoundShape.java | 2 -- .../physics/shapes/CollisionShape.java | 2 -- .../terasology/rendering/cameras/Camera.java | 13 +++++++++++++ .../rendering/logic/MeshRenderer.java | 19 ++++++++++--------- .../block/shapes/JsonBlockShapeLoader.java | 2 -- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCompoundShape.java b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCompoundShape.java index b265da498df..edea3ead17c 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCompoundShape.java +++ b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCompoundShape.java @@ -22,8 +22,6 @@ import org.joml.Quaternionfc; import org.joml.Vector3f; import org.joml.Vector3fc; -import org.terasology.math.JomlUtil; -import org.terasology.math.Transform; import org.terasology.physics.shapes.CollisionShape; import org.terasology.physics.shapes.CompoundShape; diff --git a/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java b/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java index c6dd891a413..5430622c770 100644 --- a/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java +++ b/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java @@ -20,8 +20,6 @@ import org.joml.Quaternionfc; import org.joml.Vector3fc; import org.terasology.math.AABB; -import org.terasology.math.Transform; -import org.terasology.math.geom.Quat4f; /** * The base type representing a collision shape in the physics engine. diff --git a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java index 31f9db0943f..01c724e10b0 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.cameras; +import org.joml.AABBf; import org.joml.AxisAngle4f; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -246,7 +247,19 @@ public boolean isReflected() { return reflected; } + /** + * + * @param aabb + * @return + * @deprecated This method is scheduled for removal in an upcoming version. Use the JOML implementation instead: + * {@link #hasInSight(AABBf)}. + */ + @Deprecated public boolean hasInSight(AABB aabb) { return viewFrustum.intersects(aabb); } + + public boolean hasInSight(AABBf aabb) { + return viewFrustum.intersects(aabb); + } } diff --git a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java index 5d604b6ab8c..e51cc320823 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java @@ -17,6 +17,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; +import org.joml.AABBf; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -37,9 +38,7 @@ import org.terasology.entitySystem.systems.RenderSystem; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.AABB; import org.terasology.math.JomlUtil; -import org.terasology.math.Transform; import org.terasology.network.ClientComponent; import org.terasology.network.NetworkSystem; import org.terasology.registry.In; @@ -194,26 +193,28 @@ private void renderEntitiesByMaterial(SetMultimap meshByMat for (EntityRef entity : entities) { MeshComponent meshComp = entity.getComponent(MeshComponent.class); LocationComponent location = entity.getComponent(LocationComponent.class); - - if (isHidden(entity, meshComp) || location == null || Float.isNaN(location.getWorldPosition().x) || meshComp.mesh == null || !isRelevant(entity, JomlUtil.from(location.getWorldPosition()))) { + if (isHidden(entity, meshComp) || location == null || meshComp.mesh == null) { + continue; + } + Vector3f worldPosition = location.getWorldPosition(new Vector3f()); + if (!worldPosition.isFinite() && !isRelevant(entity, worldPosition)) { continue; } + if (meshComp.mesh.isDisposed()) { logger.error("Attempted to render disposed mesh"); continue; } - worldRot.set(JomlUtil.from(location.getWorldRotation())); - worldPos.set(JomlUtil.from(location.getWorldPosition())); + worldRot.set(location.getWorldRotation(new Quaternionf())); + worldPos.set(location.getWorldPosition(new Vector3f())); float worldScale = location.getWorldScale(); - Transform toWorldSpace = new Transform(JomlUtil.from(worldPos), JomlUtil.from(worldRot), worldScale); - Vector3f offsetFromCamera = worldPos.sub(cameraPosition, new Vector3f()); matrixCameraSpace.translationRotateScale(offsetFromCamera, worldRot, worldScale); - AABB aabb = meshComp.mesh.getAABB().transform(toWorldSpace); + AABBf aabb = JomlUtil.from(meshComp.mesh.getAABB()).transform(new Matrix4f().translationRotateScale(worldPos, worldRot, worldScale)); if (worldRenderer.getActiveCamera().hasInSight(aabb)) { if (meshComp.mesh != lastMesh) { if (lastMesh != null) { diff --git a/engine/src/main/java/org/terasology/world/block/shapes/JsonBlockShapeLoader.java b/engine/src/main/java/org/terasology/world/block/shapes/JsonBlockShapeLoader.java index 6c2a4f75005..121973bba0e 100644 --- a/engine/src/main/java/org/terasology/world/block/shapes/JsonBlockShapeLoader.java +++ b/engine/src/main/java/org/terasology/world/block/shapes/JsonBlockShapeLoader.java @@ -34,9 +34,7 @@ import org.terasology.assets.format.AbstractAssetFileFormat; import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; -import org.terasology.math.JomlUtil; import org.terasology.math.Rotation; -import org.terasology.math.Transform; import org.terasology.physics.shapes.CollisionShape; import org.terasology.physics.shapes.CompoundShape; import org.terasology.physics.shapes.ConvexHullShape; From 83d0b923b1a7083368fb896146ce88294057c79e Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 12 Dec 2020 15:41:32 -0800 Subject: [PATCH 028/259] feat(JOML): migrate block placement (#4228) --- .../physics/engine/PhysicsSystem.java | 2 +- .../org/terasology/world/OnChangedBlock.java | 2 +- .../terasology/world/block/BlockRegions.java | 19 +++++++++++++++++++ .../NeighbourBlockFamilyUpdateSystem.java | 7 ++++--- .../entity/placement/BlockPlacingSystem.java | 3 ++- .../block/entity/placement/PlaceBlocks.java | 2 +- .../world/block/items/BlockItemSystem.java | 2 +- .../structure/AttachSupportRequired.java | 4 ++-- .../structure/BlockDefSupportRequired.java | 4 ++-- .../structure/BlockStructuralSupport.java | 2 +- .../BlockStructuralSupportSystem.java | 4 ++-- .../structure/SideBlockSupportRequired.java | 7 ++++--- .../internal/EntityAwareWorldProvider.java | 2 +- 13 files changed, 41 insertions(+), 19 deletions(-) diff --git a/engine/src/main/java/org/terasology/physics/engine/PhysicsSystem.java b/engine/src/main/java/org/terasology/physics/engine/PhysicsSystem.java index 98febe5e846..357957b9751 100644 --- a/engine/src/main/java/org/terasology/physics/engine/PhysicsSystem.java +++ b/engine/src/main/java/org/terasology/physics/engine/PhysicsSystem.java @@ -147,7 +147,7 @@ public void updateRigidBody(OnChangedComponent event, EntityRef entity) { @ReceiveEvent(components = {BlockComponent.class}) public void onBlockAltered(OnChangedBlock event, EntityRef entity) { - physics.awakenArea(new Vector3f(JomlUtil.from(event.getBlockPosition())), 0.6f); + physics.awakenArea(new Vector3f(event.getBlockPosition()), 0.6f); } @ReceiveEvent diff --git a/engine/src/main/java/org/terasology/world/OnChangedBlock.java b/engine/src/main/java/org/terasology/world/OnChangedBlock.java index c2204cafc12..91ad53e1463 100644 --- a/engine/src/main/java/org/terasology/world/OnChangedBlock.java +++ b/engine/src/main/java/org/terasology/world/OnChangedBlock.java @@ -16,8 +16,8 @@ package org.terasology.world; +import org.joml.Vector3i; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; /** diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegions.java b/engine/src/main/java/org/terasology/world/block/BlockRegions.java index c736b1123f9..85d6e0af2c6 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegions.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegions.java @@ -73,6 +73,25 @@ public static BlockRegion createFromCenterAndExtents(Vector3fc center, Vector3fc .setMax(new Vector3i(max, RoundingMode.FLOOR)); } + /** + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. + *

+ * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If + * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region + * will have a size of 0 along that dimension. + *

+ * Consider using {@link #encompassing(Vector3ic...)} as an alternative. + * + * @return new block region + */ + public static BlockRegion createFromMinAndSize(Vector3ic min, Vector3ic size) { + return new BlockRegion().setMin(min).setMax( + min.x() + size.x() - 1, + min.y() + size.y() - 1, + min.z() + size.z() - 1 + ); + } + /** * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing all the given positions. * diff --git a/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java b/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java index 87e9cb15291..d2947f8b7e5 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java @@ -16,6 +16,7 @@ package org.terasology.world.block.entity.neighbourUpdate; import com.google.common.collect.Sets; +import org.joml.Vector3i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; @@ -24,8 +25,8 @@ import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.UpdateSubscriberSystem; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.In; import org.terasology.world.BlockEntityRegistry; import org.terasology.world.OnChangedBlock; @@ -80,7 +81,7 @@ public void onBlockPlaced(OnBlockItemPlaced event, EntityRef entity) { return; } - processUpdateForBlockLocation(blockComponent.position); + processUpdateForBlockLocation(JomlUtil.from(blockComponent.position)); } private void notifyNeighboursOfChangedBlocks() { @@ -110,7 +111,7 @@ public void blockUpdate(OnChangedBlock event, EntityRef blockEntity) { private void processUpdateForBlockLocation(Vector3i blockLocation) { for (Side side : Side.getAllSides()) { Vector3i neighborLocation = new Vector3i(blockLocation); - neighborLocation.add(side.getVector3i()); + neighborLocation.add(side.direction()); if (worldProvider.isBlockRelevant(neighborLocation)) { Block neighborBlock = worldProvider.getBlock(neighborLocation); final BlockFamily blockFamily = neighborBlock.getBlockFamily(); diff --git a/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java b/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java index cc80bae93a6..259f9ab9130 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java @@ -21,6 +21,7 @@ import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; +import org.terasology.math.JomlUtil; import org.terasology.registry.In; import org.terasology.world.WorldComponent; import org.terasology.world.WorldProvider; @@ -34,6 +35,6 @@ public class BlockPlacingSystem extends BaseComponentSystem { @ReceiveEvent(components = {WorldComponent.class}, priority = EventPriority.PRIORITY_TRIVIAL) public void placeBlockInWorld(PlaceBlocks event, EntityRef world) { - worldProvider.setBlocks(event.getBlocks()); + worldProvider.setBlocks(JomlUtil.blockMap(event.getBlocks())); } } diff --git a/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java b/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java index e59bbeba65e..284e6e875ba 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java +++ b/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java @@ -15,9 +15,9 @@ */ package org.terasology.world.block.entity.placement; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.AbstractConsumableEvent; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import java.util.Collections; diff --git a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java index d7a4e0f438a..d3b180318c6 100644 --- a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java +++ b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java @@ -99,7 +99,7 @@ public void onPlaceBlock(ActivateEvent event, EntityRef item) { if (canPlaceBlock(block, targetBlock, placementPos)) { // TODO: Fix this for changes. if (networkSystem.getMode().isAuthority()) { - PlaceBlocks placeBlocks = new PlaceBlocks(JomlUtil.from(placementPos), block, event.getInstigator()); + PlaceBlocks placeBlocks = new PlaceBlocks(placementPos, block, event.getInstigator()); worldProvider.getWorldEntity().send(placeBlocks); if (!placeBlocks.isConsumed()) { item.send(new OnBlockItemPlaced(JomlUtil.from(placementPos), blockEntityRegistry.getBlockEntityAt(placementPos), event.getInstigator())); diff --git a/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java index 10afa5f1297..2ba27b51f74 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java @@ -15,9 +15,9 @@ */ package org.terasology.world.block.structure; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.BlockEntityRegistry; import org.terasology.world.WorldProvider; @@ -90,7 +90,7 @@ private AttachSupportRequiredComponent getComponent(Vector3i location, Map blockOverrides) { - final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition); + final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition, new Vector3i()); if (!getWorldProvider().isBlockRelevant(sideBlockPosition)) { return true; } diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java index ec3c6a3a25a..62ab7a78b99 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java @@ -15,8 +15,8 @@ */ package org.terasology.world.block.structure; +import org.joml.Vector3i; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.WorldProvider; import org.terasology.world.block.Block; @@ -34,7 +34,7 @@ public int getPriority() { public boolean isSufficientlySupported(Vector3i location, Map blockOverrides) { final Block block = getBlockWithOverrides(location, blockOverrides); if (block.isSupportRequired()) { - final Vector3i bottomLocation = Side.BOTTOM.getAdjacentPos(location); + final Vector3i bottomLocation = Side.BOTTOM.getAdjacentPos(location, new Vector3i()); return !getWorldProvider().isBlockRelevant(bottomLocation) || getBlockWithOverrides(bottomLocation, blockOverrides).isFullSide(Side.TOP); } diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java index 7d1cf7ca78e..06c9e28feed 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java @@ -15,8 +15,8 @@ */ package org.terasology.world.block.structure; +import org.joml.Vector3i; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import java.util.Map; diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java index ea1deca0f1a..af1bb0fd263 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java @@ -16,6 +16,7 @@ package org.terasology.world.block.structure; import com.google.common.collect.Sets; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; @@ -24,7 +25,6 @@ import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.logic.health.DestroyEvent; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.registry.In; import org.terasology.registry.Share; @@ -104,7 +104,7 @@ public void preventInvalidPlacement(PlaceBlocks placeBlocks, EntityRef world) { } private void validateSupportForBlockOnSide(Vector3i replacedBlockPosition, Side side) { - final Vector3i blockPosition = side.getAdjacentPos(replacedBlockPosition); + final Vector3i blockPosition = side.getAdjacentPos(replacedBlockPosition, new Vector3i()); if (worldProvider.isBlockRelevant(blockPosition)) { final Side sideReverse = side.reverse(); diff --git a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java index 70e05cb32c9..0ebd2ed4c42 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java @@ -15,14 +15,15 @@ */ package org.terasology.world.block.structure; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.prefab.PrefabManager; import org.terasology.logic.delay.DelayManager; import org.terasology.logic.delay.DelayedActionTriggeredEvent; import org.terasology.logic.health.DestroyEvent; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.BlockEntityRegistry; import org.terasology.world.WorldProvider; @@ -63,7 +64,7 @@ public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { @ReceiveEvent public void checkForSupport(DelayedActionTriggeredEvent event, EntityRef entity, BlockComponent block, SideBlockSupportRequiredComponent supportRequired) { if (event.getActionId().equals(SUPPORT_CHECK_ACTION_ID)) { - if (!isSufficientlySupported(block.position, null, Collections.emptyMap(), supportRequired)) { + if (!isSufficientlySupported(JomlUtil.from(block.position), null, Collections.emptyMap(), supportRequired)) { PrefabManager prefabManager = CoreRegistry.get(PrefabManager.class); entity.send(new DestroyEvent(entity, EntityRef.NULL, prefabManager.getPrefab("engine:supportRemovedDamage"))); } @@ -126,7 +127,7 @@ private boolean hasSupport(Vector3i blockPosition, SideBlockSupportRequiredCompo } private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map blockOverrides) { - final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition); + final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition, new Vector3i()); if (!getWorldProvider().isBlockRelevant(sideBlockPosition)) { return true; } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index b38c4f822d9..ea9debca8dc 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -195,7 +195,7 @@ private void updateBlockEntity(EntityRef blockEntity, Vector3i pos, Block oldTyp updateBlockEntityComponents(blockEntity, oldType, type, retainComponents); } - OnChangedBlock changedEvent = new OnChangedBlock(pos, type, oldType); + OnChangedBlock changedEvent = new OnChangedBlock(JomlUtil.from(pos), type, oldType); EntityRef regionEntity = blockRegionLookup.get(JomlUtil.from(pos)); if (regionEntity != null) { regionEntity.send(changedEvent); From e107ded4c539ba31fd40f44ee6857cf850193395 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 13 Dec 2020 02:39:33 -0800 Subject: [PATCH 029/259] feat(JOML): migrate ThirdPersonRemoteClientSystem (#4302) --- ...motePersonHeldItemMountPointComponent.java | 10 +++---- ...emotePersonHeldItemTransformComponent.java | 6 ++-- .../ThirdPersonRemoteClientSystem.java | 30 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemMountPointComponent.java b/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemMountPointComponent.java index 81d4aa4faa1..ae64482bdfb 100644 --- a/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemMountPointComponent.java +++ b/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemMountPointComponent.java @@ -15,11 +15,11 @@ */ package org.terasology.logic.players; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.Owns; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; /** * Only used by the client side so that held items of other players can be positioned in line with them. @@ -28,9 +28,9 @@ public class RemotePersonHeldItemMountPointComponent implements Component { @Owns public EntityRef mountPointEntity = EntityRef.NULL; - public Vector3f rotateDegrees = Vector3f.zero(); - public Vector3f translate = Vector3f.zero(); - public Quat4f rotationQuaternion; + public Vector3f rotateDegrees = new Vector3f(); + public Vector3f translate = new Vector3f(); + public Quaternionf rotationQuaternion; public float scale = 1f; } diff --git a/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemTransformComponent.java b/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemTransformComponent.java index 431569c075f..7b588592f21 100644 --- a/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemTransformComponent.java +++ b/engine/src/main/java/org/terasology/logic/players/RemotePersonHeldItemTransformComponent.java @@ -15,11 +15,11 @@ */ package org.terasology.logic.players; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; import org.terasology.rendering.logic.VisualComponent; public class RemotePersonHeldItemTransformComponent implements VisualComponent { - public Vector3f rotateDegrees = Vector3f.zero(); - public Vector3f translate = Vector3f.zero(); + public Vector3f rotateDegrees = new Vector3f(); + public Vector3f translate = new Vector3f(); public float scale = 1f; } diff --git a/engine/src/main/java/org/terasology/logic/players/ThirdPersonRemoteClientSystem.java b/engine/src/main/java/org/terasology/logic/players/ThirdPersonRemoteClientSystem.java index 524a01ab6e1..bbf320bddac 100644 --- a/engine/src/main/java/org/terasology/logic/players/ThirdPersonRemoteClientSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/ThirdPersonRemoteClientSystem.java @@ -16,6 +16,9 @@ package org.terasology.logic.players; import com.google.common.collect.Sets; +import org.joml.Math; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.Time; @@ -36,9 +39,6 @@ import org.terasology.logic.console.commandSystem.annotations.CommandParam; import org.terasology.logic.location.Location; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.TeraMath; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.network.ClientComponent; import org.terasology.registry.In; import org.terasology.rendering.logic.VisualComponent; @@ -93,10 +93,10 @@ public void ensureClientSideEntityOnHeldItemMountPoint(OnActivatedComponent even Location.removeChild(character, remotePersonHeldItemMountPointComponent.mountPointEntity); Location.attachChild(character, remotePersonHeldItemMountPointComponent.mountPointEntity, remotePersonHeldItemMountPointComponent.translate, - new Quat4f( - TeraMath.DEG_TO_RAD * remotePersonHeldItemMountPointComponent.rotateDegrees.y, - TeraMath.DEG_TO_RAD * remotePersonHeldItemMountPointComponent.rotateDegrees.x, - TeraMath.DEG_TO_RAD * remotePersonHeldItemMountPointComponent.rotateDegrees.z), + new Quaternionf().rotationYXZ( + Math.toRadians(remotePersonHeldItemMountPointComponent.rotateDegrees.y), + Math.toRadians(remotePersonHeldItemMountPointComponent.rotateDegrees.x), + Math.toRadians(remotePersonHeldItemMountPointComponent.rotateDegrees.z)), remotePersonHeldItemMountPointComponent.scale); } @@ -225,10 +225,10 @@ private void linkHeldItemLocationForRemotePlayer(EntityRef newItem, EntityRef pl Location.attachChild(mountPointComponent.mountPointEntity, currentHeldItem, heldItemTransformComponent.translate, - new Quat4f( - TeraMath.DEG_TO_RAD * heldItemTransformComponent.rotateDegrees.y, - TeraMath.DEG_TO_RAD * heldItemTransformComponent.rotateDegrees.x, - TeraMath.DEG_TO_RAD * heldItemTransformComponent.rotateDegrees.z), + new Quaternionf().rotationYXZ( + Math.toRadians(heldItemTransformComponent.rotateDegrees.y), + Math.toRadians(heldItemTransformComponent.rotateDegrees.x), + Math.toRadians(heldItemTransformComponent.rotateDegrees.z)), heldItemTransformComponent.scale); } } else { @@ -298,10 +298,10 @@ public void update(float delta) { } float addPitch = 15f * animateAmount; float addYaw = 10f * animateAmount; - locationComponent.setLocalRotation(new Quat4f( - TeraMath.DEG_TO_RAD * (mountPointComponent.rotateDegrees.y + addYaw), - TeraMath.DEG_TO_RAD * (mountPointComponent.rotateDegrees.x + addPitch), - TeraMath.DEG_TO_RAD * mountPointComponent.rotateDegrees.z)); + locationComponent.setLocalRotation(new Quaternionf().rotationYXZ( + Math.toRadians(mountPointComponent.rotateDegrees.y + addYaw), + Math.toRadians(mountPointComponent.rotateDegrees.x + addPitch), + Math.toRadians(mountPointComponent.rotateDegrees.z))); Vector3f offset = new Vector3f(0.05f * animateAmount, -0.24f * animateAmount, 0f); offset.add(mountPointComponent.translate); locationComponent.setLocalPosition(offset); From ecd7cf5adf62dc90fe94ca7e91245661587242a0 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 13 Dec 2020 05:28:18 -0800 Subject: [PATCH 030/259] feat(JOML): migrate character movment (#4303) --- .../characters/CharacterImpulseEvent.java | 2 +- .../CharacterMovementSystemUtility.java | 15 ++++---- .../logic/characters/CharacterStateEvent.java | 8 +++-- .../characters/KinematicCharacterMover.java | 14 ++++---- .../ServerCharacterPredictionSystem.java | 36 ++++++++++++------- .../characters/events/CollisionEvent.java | 2 +- .../characters/events/OnEnterBlockEvent.java | 2 +- .../terasology/physics/events/MovedEvent.java | 11 +++--- .../CharacterStateEventPositionMap.java | 14 +++++--- .../recording/RecordAndReplaySerializer.java | 20 ++++++----- 10 files changed, 73 insertions(+), 51 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java index 7ce04042114..0c228d5edca 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterImpulseEvent.java @@ -15,8 +15,8 @@ */ package org.terasology.logic.characters; -import org.terasology.entitySystem.event.Event; import org.joml.Vector3f; +import org.terasology.entitySystem.event.Event; public class CharacterImpulseEvent implements Event { Vector3f direction; diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java b/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java index 64e96f72019..f99b6de0cb5 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterMovementSystemUtility.java @@ -7,7 +7,6 @@ import org.joml.Vector3f; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import org.terasology.physics.engine.CharacterCollider; import org.terasology.physics.engine.PhysicsEngine; @@ -59,19 +58,19 @@ public void setToState(EntityRef entity, CharacterStateEvent state) { // Only set the gaze entity rotation if it is not the same as the main entity. // The character is assumed to only rotate side to side, introducing pitch makes things act strangely LocationComponent gazeLocation = gazeEntity.getComponent(LocationComponent.class); - gazeLocation.setLocalRotation(JomlUtil.from(rotation)); + gazeLocation.setLocalRotation(rotation); gazeEntity.saveComponent(gazeLocation); } } public void setToInterpolateState(EntityRef entity, CharacterStateEvent a, CharacterStateEvent b, long time) { float t = (float) (time - a.getTime()) / (b.getTime() - a.getTime()); - Vector3f newPos = a.getPosition().lerp(b.getPosition(),t); - Quaternionf newRot = a.getRotation().nlerp(b.getRotation(),t); - + Vector3f newPos = a.getPosition().lerp(b.getPosition(), t, new Vector3f()); + Quaternionf newRot = a.getRotation().nlerp(b.getRotation(), t, new Quaternionf()); + entity.updateComponent(LocationComponent.class, location -> { - location.setWorldPosition(JomlUtil.from(newPos)); - location.setWorldRotation(JomlUtil.from(newRot)); + location.setWorldPosition(newPos); + location.setWorldRotation(newRot); return location; }); @@ -111,7 +110,7 @@ public void setToExtrapolateState(EntityRef entity, CharacterStateEvent state, l private void extrapolateLocationComponent(EntityRef entity, CharacterStateEvent state, Vector3f newPos) { LocationComponent location = entity.getComponent(LocationComponent.class); - location.setWorldPosition(JomlUtil.from(newPos)); + location.setWorldPosition(newPos); location.setWorldRotation(state.getRotation()); entity.saveComponent(location); } diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java index 81cb01139bd..51d443054be 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterStateEvent.java @@ -17,7 +17,9 @@ package org.terasology.logic.characters; import org.joml.Quaternionf; +import org.joml.Quaternionfc; import org.joml.Vector3f; +import org.joml.Vector3fc; import org.joml.Vector3i; import org.terasology.network.BroadcastEvent; import org.terasology.network.NetworkEvent; @@ -56,9 +58,9 @@ public CharacterStateEvent(CharacterStateEvent previous) { public CharacterStateEvent( long time, int sequenceNumber, - Vector3f position, - Quaternionf rotation, - Vector3f velocity, + Vector3fc position, + Quaternionfc rotation, + Vector3fc velocity, float yaw, float pitch, MovementMode mode, diff --git a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java index 950144572b4..7e21e515025 100644 --- a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java +++ b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java @@ -15,6 +15,7 @@ */ package org.terasology.logic.characters; +import org.joml.Math; import org.joml.Quaternionf; import org.joml.Vector3f; import org.joml.Vector3i; @@ -155,7 +156,7 @@ private void checkBlockEntry(EntityRef entity, Vector3i oldPosition, Vector3i ne for (int y = 0; y < characterHeightInBlocks; y++) { // send a block enter/leave event for this character - entity.send(new OnEnterBlockEvent(oldBlocks[y], newBlocks[y], JomlUtil.from(new Vector3i(0, y, 0)))); + entity.send(new OnEnterBlockEvent(oldBlocks[y], newBlocks[y], new Vector3i(0, y, 0))); } } } @@ -338,10 +339,11 @@ private Vector3f extractResidualMovement(Vector3f hitNormal, Vector3f direction, private void followToParent(final CharacterStateEvent state, EntityRef entity) { LocationComponent locationComponent = entity.getComponent(LocationComponent.class); if (!locationComponent.getParent().equals(EntityRef.NULL)) { - Vector3f velocity = new Vector3f(locationComponent.getWorldPosition(new Vector3f())); + Vector3f position = locationComponent.getWorldPosition(new Vector3f()); + Vector3f velocity = new Vector3f(position); velocity.sub(state.getPosition()); state.getVelocity().set(velocity); - state.getPosition().set(locationComponent.getWorldPosition(new Vector3f())); + state.getPosition().set(position); } } @@ -576,9 +578,9 @@ private void updateRotation(CharacterMovementComponent movementComp, CharacterSt CharacterMoveInputEvent input) { if (movementComp.faceMovementDirection && result.getVelocity().lengthSquared() > 0.01f) { float yaw = (float) Math.atan2(result.getVelocity().x, result.getVelocity().z); - result.getRotation().set(0, 1, 0, yaw); + result.getRotation().setAngleAxis(yaw, 0, 1, 0); } else { - result.getRotation().set(new Quaternionf().rotationYXZ(org.joml.Math.toRadians(input.getYaw()), 0, 0)); + result.getRotation().set(new Quaternionf().rotationYXZ(Math.toRadians(input.getYaw()), 0, 0)); } } @@ -645,7 +647,7 @@ private void walk(final CharacterMovementComponent movementComp, final Character distanceMoved.sub(state.getPosition()); state.getPosition().set(moveResult.getFinalPosition()); if (input.isFirstRun() && distanceMoved.length() > 0) { - entity.send(new MovedEvent(new Vector3f(distanceMoved), new Vector3f(state.getPosition()))); + entity.send(new MovedEvent(distanceMoved, state.getPosition())); } // Upon hitting solid ground, reset the number of jumps back to the maximum value. diff --git a/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java b/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java index abba55a1284..822388005ee 100644 --- a/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/ServerCharacterPredictionSystem.java @@ -20,6 +20,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.joml.Quaternionf; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.Time; @@ -35,7 +36,6 @@ import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; import org.terasology.math.JomlUtil; -import org.joml.Vector3f; import org.terasology.network.NetworkSystem; import org.terasology.physics.engine.CharacterCollider; import org.terasology.physics.engine.PhysicsEngine; @@ -52,7 +52,8 @@ @RegisterSystem(RegisterMode.AUTHORITY) @Share(PredictionSystem.class) -public class ServerCharacterPredictionSystem extends BaseComponentSystem implements UpdateSubscriberSystem, PredictionSystem { +public class ServerCharacterPredictionSystem extends BaseComponentSystem implements UpdateSubscriberSystem, + PredictionSystem { public static final int RENDER_DELAY = 100; public static final int MAX_INPUT_OVERFLOW = 100; public static final int MAX_INPUT_UNDERFLOW = 100; @@ -98,7 +99,8 @@ public void initialise() { characterMovementSystemUtility = new CharacterMovementSystemUtility(physics); } - @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, AliveCharacterComponent.class}) + @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, + AliveCharacterComponent.class}) public void onCreate(final OnActivatedComponent event, final EntityRef entity) { physics.getCharacterCollider(entity); CircularBuffer stateBuffer = CircularBuffer.create(BUFFER_SIZE); @@ -106,7 +108,8 @@ public void onCreate(final OnActivatedComponent event, final EntityRef entity) { characterStates.put(entity, stateBuffer); } - @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, AliveCharacterComponent.class}) + @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, + AliveCharacterComponent.class}) public void onDestroy(final BeforeDeactivateComponent event, final EntityRef entity) { physics.removeCharacterCollider(entity); characterStatesToRemove.add(entity); @@ -114,7 +117,8 @@ public void onDestroy(final BeforeDeactivateComponent event, final EntityRef ent } @ReceiveEvent(components = {AliveCharacterComponent.class}) - public void onSetMovementModeEvent(SetMovementModeEvent event, EntityRef character, CharacterMovementComponent movementComponent) { + public void onSetMovementModeEvent(SetMovementModeEvent event, EntityRef character, + CharacterMovementComponent movementComponent) { CircularBuffer stateBuffer = characterStates.get(character); CharacterStateEvent lastState = stateBuffer.getLast(); CharacterStateEvent newState = new CharacterStateEvent(lastState); @@ -128,7 +132,8 @@ public void onSetMovementModeEvent(SetMovementModeEvent event, EntityRef charact characterMovementSystemUtility.setToState(character, newState); } - @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, AliveCharacterComponent.class}) + @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, + AliveCharacterComponent.class}) public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { CharacterCollider characterCollider = physics.getCharacterCollider(entity); if (characterCollider.isPending()) { @@ -137,7 +142,7 @@ public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { } CircularBuffer stateBuffer = characterStates.get(entity); CharacterStateEvent lastState = stateBuffer.getLast(); - float delta = input.getDeltaMs() + lastState.getTime() - (time.getGameTimeInMs() + MAX_INPUT_OVERFLOW ); + float delta = input.getDeltaMs() + lastState.getTime() - (time.getGameTimeInMs() + MAX_INPUT_OVERFLOW); if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) { delta -= MAX_INPUT_OVERFLOW_REPLAY_INCREASE; } @@ -145,10 +150,11 @@ public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { CharacterStateEvent newState = stepState(input, lastState, entity); stateBuffer.add(newState); - if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) { + if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) { characterStateEventPositionMap.updateCharacterStateEvent(newState); } else if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.RECORDING) { - characterStateEventPositionMap.add(newState.getSequenceNumber(), JomlUtil.from(newState.getPosition()), JomlUtil.from(newState.getVelocity())); + characterStateEventPositionMap.add(newState.getSequenceNumber(), newState.getPosition(), + newState.getVelocity()); } characterMovementSystemUtility.setToState(entity, newState); @@ -158,7 +164,8 @@ public void onPlayerInput(CharacterMoveInputEvent input, EntityRef entity) { } } - @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, AliveCharacterComponent.class}) + @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, + AliveCharacterComponent.class}) public void onTeleport(CharacterTeleportEvent event, EntityRef entity) { CircularBuffer stateBuffer = characterStates.get(entity); CharacterStateEvent lastState = stateBuffer.getLast(); @@ -170,7 +177,8 @@ public void onTeleport(CharacterTeleportEvent event, EntityRef entity) { } - @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, AliveCharacterComponent.class}) + @ReceiveEvent(components = {CharacterMovementComponent.class, LocationComponent.class, + AliveCharacterComponent.class}) public void onImpulse(CharacterImpulseEvent event, EntityRef entity) { Vector3f impulse = event.getDirection(); @@ -186,10 +194,12 @@ public void onImpulse(CharacterImpulseEvent event, EntityRef entity) { private CharacterStateEvent createInitialState(EntityRef entity) { LocationComponent location = entity.getComponent(LocationComponent.class); - return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(new Vector3f()), location.getWorldRotation(new Quaternionf()), new Vector3f(), 0, 0, MovementMode.WALKING, false); + return new CharacterStateEvent(time.getGameTimeInMs(), 0, location.getWorldPosition(new Vector3f()), + location.getWorldRotation(new Quaternionf()), new Vector3f(), 0, 0, MovementMode.WALKING, false); } - private CharacterStateEvent stepState(CharacterMoveInputEvent input, CharacterStateEvent lastState, EntityRef entity) { + private CharacterStateEvent stepState(CharacterMoveInputEvent input, CharacterStateEvent lastState, + EntityRef entity) { return characterMover.step(lastState, input, entity); } diff --git a/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java index ac6e8443d1a..aaabddcf217 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/CollisionEvent.java @@ -15,8 +15,8 @@ */ package org.terasology.logic.characters.events; -import org.terasology.entitySystem.event.Event; import org.joml.Vector3f; +import org.terasology.entitySystem.event.Event; /** */ diff --git a/engine/src/main/java/org/terasology/logic/characters/events/OnEnterBlockEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/OnEnterBlockEvent.java index 303a5e514e7..ca9dc6bb155 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/OnEnterBlockEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/OnEnterBlockEvent.java @@ -15,8 +15,8 @@ */ package org.terasology.logic.characters.events; +import org.joml.Vector3i; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; /** diff --git a/engine/src/main/java/org/terasology/physics/events/MovedEvent.java b/engine/src/main/java/org/terasology/physics/events/MovedEvent.java index b4da9fe825e..94e93ff8f8f 100644 --- a/engine/src/main/java/org/terasology/physics/events/MovedEvent.java +++ b/engine/src/main/java/org/terasology/physics/events/MovedEvent.java @@ -16,16 +16,17 @@ package org.terasology.physics.events; -import org.terasology.entitySystem.event.Event; +import org.joml.Vector3f; import org.joml.Vector3fc; +import org.terasology.entitySystem.event.Event; public class MovedEvent implements Event { - private Vector3fc delta; - private Vector3fc finalPosition; + private Vector3f delta = new Vector3f(); + private Vector3f finalPosition = new Vector3f(); public MovedEvent(Vector3fc delta, Vector3fc finalPosition) { - this.delta = delta; - this.finalPosition = finalPosition; + this.delta.set(delta); + this.finalPosition.set(finalPosition); } public Vector3fc getDelta() { diff --git a/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java b/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java index 8542a763106..d8caf01ff14 100644 --- a/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java +++ b/engine/src/main/java/org/terasology/recording/CharacterStateEventPositionMap.java @@ -15,9 +15,8 @@ */ package org.terasology.recording; +import org.joml.Vector3f; import org.terasology.logic.characters.CharacterStateEvent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import java.util.HashMap; import java.util.Map; @@ -29,7 +28,10 @@ */ public class CharacterStateEventPositionMap { - /** Map in which the key is the "sequenceNumber" of the CharacterStateEvent and the value is an array with the "position" and "velocity" variables. */ + /** + * Map in which the key is the "sequenceNumber" of the CharacterStateEvent and the value is an array with the + * "position" and "velocity" variables. + */ private Map idToData; public CharacterStateEventPositionMap() { @@ -38,6 +40,7 @@ public CharacterStateEventPositionMap() { /** * Add a new "position" and "velocity" to the map. + * * @param sequenceNumber the sequenceNumber of the CharacterStateEvent. * @param position the position of the event. * @param velocity the velocity of the event. @@ -67,11 +70,12 @@ public void reset() { /** * Used in a replay to update a CharacterStateEvent with the correct values of "position" and "velocity". + * * @param event the event to be updated. */ public void updateCharacterStateEvent(CharacterStateEvent event) { Vector3f[] data = this.idToData.get(event.getSequenceNumber()); - event.setPosition(JomlUtil.from(data[0])); - event.setVelocity(JomlUtil.from(data[1])); + event.setPosition(data[0]); + event.setVelocity(data[1]); } } diff --git a/engine/src/main/java/org/terasology/recording/RecordAndReplaySerializer.java b/engine/src/main/java/org/terasology/recording/RecordAndReplaySerializer.java index fe88443df8a..10709738d28 100644 --- a/engine/src/main/java/org/terasology/recording/RecordAndReplaySerializer.java +++ b/engine/src/main/java/org/terasology/recording/RecordAndReplaySerializer.java @@ -21,16 +21,16 @@ import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonWriter; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.module.ModuleManager; import org.terasology.engine.paths.PathManager; import org.terasology.entitySystem.entity.EntityManager; -import org.terasology.math.geom.Vector3f; import org.terasology.reflection.TypeRegistry; -import java.io.FileWriter; import java.io.FileReader; +import java.io.FileWriter; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; @@ -80,6 +80,7 @@ public void serializeRecordAndReplayData() { /** * Serialize RecordedEvents. + * * @param recordingPath path where the data should be saved. */ public void serializeRecordedEvents(String recordingPath) { @@ -104,6 +105,7 @@ public void deserializeRecordAndReplayData() { /** * Deserialize RecordedEvents. + * * @param recordingPath path where the data was saved. */ void deserializeRecordedEvents(String recordingPath) { @@ -125,10 +127,11 @@ private void serializeFileAmount(Gson gson, String recordingPath) { } private void deserializeFileAmount(Gson gson, String recordingPath) { - try (FileReader fileReader = new FileReader(recordingPath + FILE_AMOUNT)){ + try (FileReader fileReader = new FileReader(recordingPath + FILE_AMOUNT)) { JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse(fileReader); - Type typeOfCount = new TypeToken() { }.getType(); + Type typeOfCount = new TypeToken() { + }.getType(); recordAndReplayUtils.setFileAmount(gson.fromJson(jsonElement, typeOfCount)); logger.info("File Amount Deserialization completed!"); } catch (Exception e) { @@ -152,7 +155,8 @@ private void deserializeCharacterStateEventPositionMap(Gson gson, String recordi try (FileReader fileReader = new FileReader(recordingPath + STATE_EVENT_POSITION)) { JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse(fileReader); - Type typeOfHashMap = new TypeToken>() { }.getType(); + Type typeOfHashMap = new TypeToken>() { + }.getType(); Map previousMap = gson.fromJson(jsonElement, typeOfHashMap); characterStateEventPositionMap.setIdToData(previousMap); logger.info("CharacterStateEvent positions Deserialization completed!"); @@ -172,12 +176,13 @@ private void serializeAttackEventExtraRecorder(Gson gson, String recordingPath) logger.error("Error while serializing AttackEvent extras:", e); } } - + private void deserializeAttackEventExtraRecorder(Gson gson, String recordingPath) { try (FileReader fileReader = new FileReader(recordingPath + DIRECTION_ORIGIN_LIST)) { JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse(fileReader); - Type type = new TypeToken>() {}.getType(); + Type type = new TypeToken>() { + }.getType(); ArrayList list = gson.fromJson(jsonElement, type); directionAndOriginPosRecorderList.setList(list); logger.info("AttackEvent extras deserialization completed!"); @@ -185,5 +190,4 @@ private void deserializeAttackEventExtraRecorder(Gson gson, String recordingPath logger.error("Error while deserializing AttackEvent extras:", e); } } - } From afc15bc958a6c3d9426b28a22156ae4a67bac8fd Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 13 Dec 2020 06:04:08 -0800 Subject: [PATCH 031/259] feat(JOML): migrate camera target system (#4262) --- .../cameraTarget/CameraTargetSystem.java | 21 ++++++++++--------- .../terasology/logic/players/LocalPlayer.java | 7 ++++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/engine/src/main/java/org/terasology/input/cameraTarget/CameraTargetSystem.java b/engine/src/main/java/org/terasology/input/cameraTarget/CameraTargetSystem.java index 746a1f370e0..becc814b046 100644 --- a/engine/src/main/java/org/terasology/input/cameraTarget/CameraTargetSystem.java +++ b/engine/src/main/java/org/terasology/input/cameraTarget/CameraTargetSystem.java @@ -24,7 +24,6 @@ import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import org.terasology.physics.CollisionGroup; import org.terasology.physics.HitResult; @@ -112,8 +111,8 @@ public void update(float delta) { } - HitResult hitInfo = physics.rayTrace(JomlUtil.from(localPlayer.getViewPosition()), - JomlUtil.from(localPlayer.getViewDirection()), targetDistance, filter); + HitResult hitInfo = physics.rayTrace(localPlayer.getViewPosition(new Vector3f()), + localPlayer.getViewDirection(new Vector3f()), targetDistance, filter); updateFocalDistance(hitInfo, delta); Vector3i newBlockPos = null; @@ -144,7 +143,7 @@ private void updateFocalDistance(HitResult hitInfo, float delta) { if (hitInfo.isHit()) { Vector3f playerToTargetRay = new Vector3f(); //calculate the distance from the player to the hit point - hitInfo.getHitPoint().sub(JomlUtil.from(localPlayer.getViewPosition()), playerToTargetRay); + hitInfo.getHitPoint().sub(localPlayer.getViewPosition(new Vector3f()), playerToTargetRay); //gradually adjust focalDistance from it's current value to the hit point distance focalDistance = TeraMath.lerp(focalDistance, playerToTargetRay.length(), delta * focusRate); //if nothing was hit, gradually adjust the focusDistance to the maximum length of the update function trace @@ -157,13 +156,15 @@ private void updateFocalDistance(HitResult hitInfo, float delta) { public String toString() { if (targetBlockPos != null) { + Vector3f pos = localPlayer.getViewPosition(new Vector3f()); + Vector3f dir = localPlayer.getViewDirection(new Vector3f()); return String.format("From: %f %f %f, Dir: %f %f %f, Hit %d %d %d %f %f %f", - localPlayer.getViewPosition().x, - localPlayer.getViewPosition().y, - localPlayer.getViewPosition().z, - localPlayer.getViewDirection().x, - localPlayer.getViewDirection().y, - localPlayer.getViewDirection().z, + pos.x, + pos.y, + pos.z, + dir.x, + dir.y, + dir.z, targetBlockPos.x, targetBlockPos.y, targetBlockPos.z, diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java index 1fc4e01e00e..a0857190559 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java @@ -175,7 +175,12 @@ public Quaternionf getRotation(Quaternionf dest) { } return dest; } - + /** + * @return + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #getViewPosition(org.joml.Vector3f)}. + */ + @Deprecated public Vector3f getViewPosition() { return getViewPosition(new Vector3f()); } From f5e1495fdbc8645e309f7529a6ca5b7a3bd671a7 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Wed, 16 Dec 2020 08:17:09 +0000 Subject: [PATCH 032/259] Add borders to atlas subtextures (#4311) Co-authored-by: Tobias Nett Co-authored-by: DarkWeird --- .../rendering/assets/atlas/AtlasFormat.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java index b4b9e1c95cb..e57949a76b7 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java +++ b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java @@ -45,6 +45,7 @@ */ @RegisterAssetFileFormat public class AtlasFormat extends AbstractAssetFileFormat { + public static final float BORDER_SIZE = 0.0001f; private static final Logger logger = LoggerFactory.getLogger(AtlasFormat.class); @@ -108,10 +109,10 @@ private void process(FreeformDefinition freeform, Texture texture, Vector2i size Vector2f min = new Vector2f((float) freeform.getMin().x / size.x, (float) freeform.getMin().y / size.y); if (freeform.getSize() != null) { Vector2f itemSize = new Vector2f((float) freeform.getSize().x / size.x, (float) freeform.getSize().y / size.y); - out.put(new Name(freeform.getName()), new SubtextureData(texture, Rect2f.createFromMinAndSize(min, itemSize))); + out.put(new Name(freeform.getName()), new SubtextureData(texture, shrinkRegion(Rect2f.createFromMinAndSize(min, itemSize)))); } else if (freeform.getMax() != null) { Vector2f max = new Vector2f((float) freeform.getMax().x / size.x, (float) freeform.getMax().y / size.y); - out.put(new Name(freeform.getName()), new SubtextureData(texture, Rect2f.createFromMinAndMax(min, max))); + out.put(new Name(freeform.getName()), new SubtextureData(texture, shrinkRegion(Rect2f.createFromMinAndMax(min, max)))); } } @@ -138,7 +139,7 @@ private void process(GridDefinition grid, Texture texture, Vector2i size, Map Date: Sat, 19 Dec 2020 17:27:18 -0800 Subject: [PATCH 033/259] add missing absolute value for box collider extent (#4325) --- .../org/terasology/physics/bullet/shapes/BulletBoxShape.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletBoxShape.java b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletBoxShape.java index 868efda129e..d747fbb4e37 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletBoxShape.java +++ b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletBoxShape.java @@ -32,7 +32,7 @@ public BulletBoxShape(Vector3f halfExtents) { @Override public CollisionShape rotate(Quaternionf rot) { Vector3f halfExtentsWithMargin = new Vector3f(boxShape.getHalfExtentsWithMargin()); - return new BulletBoxShape(halfExtentsWithMargin.rotate(rot)); + return new BulletBoxShape(halfExtentsWithMargin.rotate(rot).absolute()); } @Override From b77dd4e2d993c48078795e2fed92acba0c9359ae Mon Sep 17 00:00:00 2001 From: QuentinAndre11 <62743754+QuentinAndre11@users.noreply.github.com> Date: Sun, 20 Dec 2020 19:41:35 +0100 Subject: [PATCH 034/259] fix!(BlockRegion): Rewrite of BlockRegion (#4321) Fixes #4086 This ended up to be a rewrite of `BlockRegion` to be no longer backed by an AABBi, but just by 6 integer values. Every `BlockRegion` _should_ be valid now, and all modifications on a `BlockRegion` are guarded by precondition checks. Co-authored-by: DUMONT Joanne Co-authored-by: Michael Pollind Co-authored-by: Tobias Nett --- .../org/terasology/math/BlockRegionTest.java | 250 ----- .../org/terasology/math/ChunkMathTest.java | 8 +- .../mathTypes/BlockRegionTypeHandlerTest.java | 7 +- .../world/block/BlockRegionIterableTest.java | 2 +- .../world/block/BlockRegionTest.java | 603 +++++++++++ .../LocalChunkProviderTest.java | 9 +- .../java/org/terasology/math/ChunkMath.java | 3 +- .../java/org/terasology/math/JomlUtil.java | 3 +- .../mathTypes/BlockRegionTypeHandler.java | 18 +- .../terasology/world/block/BlockRegion.java | 943 +++++++++++------- .../world/block/BlockRegionIterable.java | 13 +- .../terasology/world/block/BlockRegions.java | 37 +- .../block/regions/BlockRegionComponent.java | 8 +- .../propagation/StandardBatchPropagator.java | 43 +- 14 files changed, 1258 insertions(+), 689 deletions(-) delete mode 100644 engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java create mode 100644 engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java diff --git a/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java deleted file mode 100644 index d6139650c56..00000000000 --- a/engine-tests/src/test/java/org/terasology/math/BlockRegionTest.java +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.math; - -import com.google.common.collect.Sets; -import org.joml.Vector3f; -import org.joml.Vector3fc; -import org.joml.Vector3i; -import org.joml.Vector3ic; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * - */ -public class BlockRegionTest { - - @Test - public void testCreateRegionWithMinAndSize() { - List mins = Arrays.asList(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i(3, 4, 5)); - List size = Arrays.asList(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(8, 5, 2)); - List expectedMax = Arrays.asList(new Vector3i(), new Vector3i(3, 3, 3), new Vector3i(10, 8, 6)); - - for (int i = 0; i < mins.size(); ++i) { - BlockRegion region = new BlockRegion().setMin(mins.get(i)).setSize(size.get(i)); - assertEquals(mins.get(i), region.getMin(new Vector3i())); - assertEquals(size.get(i), region.getSize(new Vector3i())); - assertEquals(expectedMax.get(i), region.getMax(new Vector3i())); - } - } - - private static Stream createFromMinAndMaxArgs() { - return Stream.of( - Arguments.of(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i()), - Arguments.of(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(3, 3, 3)), - Arguments.of(new Vector3i(3, 4, 5), new Vector3i(8, 5, 2), new Vector3i(10, 8, 6)), - Arguments.of(new Vector3i(1, 1, 1), new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), - Arguments.of(new Vector3i(0, 1, 0), new Vector3i(2, 0, 2), new Vector3i(1, 0, 1)) - ); - } - - @ParameterizedTest - @MethodSource("createFromMinAndMaxArgs") - public void createFromMinAndMaxArgs(Vector3i min, Vector3i expectedSize, Vector3i max) { - BlockRegion region = BlockRegions.createFromMinAndMax(min, max); - assertEquals(min, region.getMin(new Vector3i()), "min"); - assertEquals(max, region.getMax(new Vector3i()), "max"); - assertEquals(expectedSize, region.getSize(new Vector3i()), "size"); - } - - private static Stream createEncompassingArgs() { - return Stream.of( - Arguments.of(new Vector3i(1, 1, 1), - new Vector3i[]{new Vector3i(), new Vector3i()}), - Arguments.of(new Vector3i(3, 3, 3), - new Vector3i[]{new Vector3i(1, 1, 1), new Vector3i(3, 3, 3)}), - Arguments.of(new Vector3i(3, 3, 3), - new Vector3i[]{new Vector3i(3, 3, 3), new Vector3i(1, 1, 1)}), - Arguments.of(new Vector3i(2, 2, 2), - new Vector3i[]{new Vector3i(0, 1, 0), new Vector3i(1, 0, 1)}), - Arguments.of(new Vector3i(2, 3, 4), - new Vector3i[]{new Vector3i(0, 1, 0), new Vector3i(1, 0, 1), new Vector3i(0, -1, 3)}) - ); - } - - @ParameterizedTest - @MethodSource("createEncompassingArgs") - public void createEncompassingTest(Vector3i expectedSize, Vector3i[] positions) { - Vector3i min = Arrays.stream(positions).reduce(new Vector3i(Integer.MAX_VALUE), Vector3i::min); - Vector3i max = Arrays.stream(positions).reduce(new Vector3i(Integer.MIN_VALUE), Vector3i::max); - - BlockRegion region = BlockRegions.encompassing(positions); - assertEquals(min, region.getMin(new Vector3i()), "min of " + region); - assertEquals(max, region.getMax(new Vector3i()), "max of " + region); - assertEquals(expectedSize, region.getSize(new Vector3i()), "size of " + region); - } - - @Test - public void testCreateRegionWithBounds() { - BlockRegion expectedRegion = new BlockRegion(new Vector3i(-2, 4, -16), new Vector3i(4, 107, 0)); - List vec1 = Arrays.asList(new Vector3i(-2, 4, -16), new Vector3i(4, 4, -16), new Vector3i(-2, 107, - -16), new Vector3i(-2, 4, 0), - new Vector3i(4, 107, -16), new Vector3i(4, 4, 0), new Vector3i(-2, 107, 0), new Vector3i(4, 107, 0)); - List vec2 = Arrays.asList(new Vector3i(4, 107, 0), new Vector3i(-2, 107, 0), new Vector3i(4, 4, 0), - new Vector3i(4, 107, -16), - new Vector3i(-2, 4, 0), new Vector3i(-2, 107, -16), new Vector3i(4, 4, -16), new Vector3i(-2, 4, -16)); - for (int i = 0; i < vec1.size(); ++i) { - BlockRegion target = new BlockRegion().union(vec1.get(i)).union(vec2.get(i)); - assertEquals(expectedRegion, target); - } - } - - @Test - public void testRegionInvalidIfMaxLessThanMin() { - BlockRegion region = new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(-1, 0, 0)); - assertFalse(region.isValid()); - } - - @Test - public void testIterateRegion() { - Vector3i min = new Vector3i(2, 5, 7); - Vector3i max = new Vector3i(10, 11, 12); - BlockRegion region = new BlockRegion(min, max); - - Set expected = Sets.newHashSet(); - for (int x = min.x; x <= max.x; ++x) { - for (int y = min.y; y <= max.y; ++y) { - for (int z = min.z; z <= max.z; ++z) { - expected.add(new Vector3i(x, y, z)); - } - } - } - - - for (Vector3ic pos : BlockRegions.iterableInPlace(region)) { - assertTrue(expected.contains(pos), "unexpected position: " + pos); - expected.remove(pos); - } - - assertEquals(0, expected.size(), "All vectors provided"); - } - - @Test - public void testSimpleIntersect() { - BlockRegion region1 = new BlockRegion(new Vector3i(), new Vector3i(32, 32, 32)); - BlockRegion region2 = new BlockRegion(new Vector3i(1, 1, 1), new Vector3i(17, 17, 17)); - assertEquals(region2, region1.intersection(region2, new BlockRegion())); - } - - @Test - public void testNonTouchingIntersect() { - BlockRegion region1 = new BlockRegion(new Vector3i(), new Vector3i(32, 32, 32)); - BlockRegion region2 = new BlockRegion(new Vector3i(103, 103, 103), new Vector3i(170, 170, 170)); - assertFalse(region1.intersection(region2, new BlockRegion()).isValid()); - } - - @Test - public void testEncompasses() { - BlockRegion region = new BlockRegion().union(new Vector3i()).setSize(new Vector3i(1, 1, 1)); - assertTrue(region.containsBlock(0, 0, 0)); - - assertFalse(region.containsBlock(1, 0, 0)); - assertFalse(region.containsBlock(1, 0, 1)); - assertFalse(region.containsBlock(0, 0, 1)); - assertFalse(region.containsBlock(-1, 0, -1)); - assertFalse(region.containsBlock(-1, 0, 0)); - assertFalse(region.containsBlock(-1, 0, -1)); - assertFalse(region.containsBlock(0, 0, -1)); - - assertFalse(region.containsBlock(1, 1, 0)); - assertFalse(region.containsBlock(1, 1, 1)); - assertFalse(region.containsBlock(0, 1, 1)); - assertFalse(region.containsBlock(-1, 1, -1)); - assertFalse(region.containsBlock(-1, 1, 0)); - assertFalse(region.containsBlock(-1, 1, -1)); - assertFalse(region.containsBlock(0, 1, -1)); - - assertFalse(region.containsBlock(1, -1, 0)); - assertFalse(region.containsBlock(1, -1, 1)); - assertFalse(region.containsBlock(0, -1, 1)); - assertFalse(region.containsBlock(-1, -1, -1)); - assertFalse(region.containsBlock(-1, -1, 0)); - assertFalse(region.containsBlock(-1, -1, -1)); - assertFalse(region.containsBlock(0, -1, -1)); - } - - @Test - public void testCorrectBoundsFlip() { - Vector3i min = new Vector3i(0, 0, 0); - Vector3i max = new Vector3i(1, 1, 1); - BlockRegion region = BlockRegions.createFromMinAndMax(max, min); - region.correctBounds(); - - assertEquals(min, region.getMin(new Vector3i())); - assertEquals(max, region.getMax(new Vector3i())); - } - - @Test - public void testCorrectBoundsMixed() { - Vector3i min = new Vector3i(0, 0, 0); - Vector3i max = new Vector3i(1, 1, 1); - BlockRegion region = BlockRegions.createFromMinAndMax(1, 0, 1, 0, 1, 0); - region.correctBounds(); - - assertEquals(min, region.getMin(new Vector3i())); - assertEquals(max, region.getMax(new Vector3i())); - } - - private static Stream testCenterArgs() { - return Stream.of( - Arguments.of( - new BlockRegion(), - new Vector3f(Float.NaN) - ), - // creating from min and max - Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), - new Vector3f(0.5f, 0.5f, 0.5f) - ), - Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)), - new Vector3f(1f, 1f, 1f) - ), - Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(1, 1, 1)), - new Vector3f(0.5f, 0.5f, 0.5f) - ), - Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(2, 2, 2)), - new Vector3f(1.5f, 1.5f, 1.5f) - ), - // creating from center and extents - Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)), - new Vector3f(0.5f, 0.5f, 0.5f) - ), - Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0.5f, 0.5f, 0.5f), new Vector3f(0.5f, - 0.5f, 0.5f)), - new Vector3f(1f, 1f, 1f) - ), - Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0.49f, 0.49f, 0.49f), new Vector3f(0.5f, - 0.5f, 0.5f)), - new Vector3f(.5f, .5f, .5f) - ) - - ); - } - - @ParameterizedTest - @MethodSource("testCenterArgs") - public void testCenter(BlockRegion region, Vector3fc expectedCenter) { - assertEquals(expectedCenter, region.center(new Vector3f())); - } -} diff --git a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java index 20c732e9a24..d50bfa04155 100644 --- a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java +++ b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java @@ -21,7 +21,7 @@ import org.terasology.context.internal.MockContext; import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; -import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -97,11 +97,11 @@ public void testCalcChunkPos() { @Test public void testChunkRegionAroundWorldPos() { assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 100), - new BlockRegion(-4, -2, -4, 3, 1, 3)); + BlockRegions.createFromMinAndMax(-4, -2, -4, 3, 1, 3)); assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(-30, -30, -30), 100), - new BlockRegion(-5, -3, -5, 2, 1, 2)); + BlockRegions.createFromMinAndMax(-5, -3, -5, 2, 1, 2)); assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 10), - new BlockRegion(-1, -1, -1, 0, 0, 0)); + BlockRegions.createFromMinAndMax(-1, -1, -1, 0, 0, 0)); } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java index a4820825462..b2bfeae63c6 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java @@ -14,6 +14,7 @@ import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.gson.GsonBuilderFactory; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; public class BlockRegionTypeHandlerTest extends MathTypeAssert { public static class AABBBlockRegion1Test { @@ -23,16 +24,14 @@ public static class AABBBlockRegion1Test { private final Reflections reflections = new Reflections(getClass().getClassLoader()); private final TypeHandlerLibrary typeHandlerLibrary = TypeHandlerLibraryImpl.withReflections(reflections); - private AABBiTypeHandler handler = new AABBiTypeHandler(); private final Gson gson = - GsonBuilderFactory.createGsonBuilderWithTypeSerializationLibrary(typeHandlerLibrary) - .create(); + GsonBuilderFactory.createGsonBuilderWithTypeSerializationLibrary(typeHandlerLibrary).create(); @Test public void testSerializeBlockRegion() { AABBBlockRegion1Test aabb1 = new AABBBlockRegion1Test(); - aabb1.a1 = new BlockRegion(5, 5, 5, 13, 12, 14); + aabb1.a1 = BlockRegions.createFromMinAndMax(5, 5, 5, 13, 12, 14); aabb1.a2 = new AABBi(3, 5, 5, 22, 12, 14); JsonElement tree = gson.toJsonTree(aabb1); diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java index 2cd1759f7e7..8f1c15e97ee 100644 --- a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java @@ -71,7 +71,7 @@ public void testBoxOfBlocksRegion() { } private List expectedPositions(BlockRegion region) { - List result = new ArrayList<>(region.getSizeX() * region.getSizeY() * region.getSizeZ()); + List result = new ArrayList<>(region.sizeX() * region.sizeY() * region.sizeZ()); for (int x = region.getMinX(); x <= region.getMaxX(); x++) { for (int y = region.getMinY(); y <= region.getMaxY(); y++) { for (int z = region.getMinZ(); z <= region.getMaxZ(); z++) { diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java new file mode 100644 index 00000000000..57245d503e7 --- /dev/null +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java @@ -0,0 +1,603 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.block; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.joml.AABBf; +import org.joml.LineSegmentf; +import org.joml.Rayf; +import org.joml.Spheref; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.entitySystem.entity.internal.PojoEntityManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * + */ +public class BlockRegionTest { + + @Test + void getMinMax() { + final Vector3i min = new Vector3i(1, 2, 3); + final Vector3i max = new Vector3i(7, 8, 9); + final BlockRegion region = + BlockRegions.createFromMinAndMax(min, max); + + assertEquals(min, region.getMin(new Vector3i())); + assertEquals(max, region.getMax(new Vector3i())); + + assertEquals(min.x, region.getMinX()); + assertEquals(region.getMinX(), region.minX()); + assertEquals(min.y, region.getMinY()); + assertEquals(region.getMinY(), region.minY()); + assertEquals(min.z, region.getMinZ()); + assertEquals(region.getMinZ(), region.minZ()); + + assertEquals(max.x, region.getMaxX()); + assertEquals(region.getMaxX(), region.maxX()); + assertEquals(max.y, region.getMaxY()); + assertEquals(region.getMaxY(), region.maxY()); + assertEquals(max.z, region.getMaxZ()); + assertEquals(region.getMaxZ(), region.maxZ()); + } + + @Test + void setMinMax() { + BlockRegion region = new BlockRegion(new Vector3i()); + + assertEquals(-1, region.minX(-1).minX()); + assertEquals(-2, region.minY(-2).minY()); + assertEquals(-3, region.minZ(-3).minZ()); + + assertEquals(1, region.maxX(1).maxX()); + assertEquals(2, region.maxY(2).maxY()); + assertEquals(3, region.maxZ(3).maxZ()); + } + + @Test + void setMinMaxInvalid() { + BlockRegion region = new BlockRegion(new Vector3i()); + assertThrows(IllegalArgumentException.class, () -> region.minX(2)); + assertThrows(IllegalArgumentException.class, () -> region.minY(2)); + assertThrows(IllegalArgumentException.class, () -> region.minZ(2)); + + assertThrows(IllegalArgumentException.class, () -> region.maxX(-1)); + assertThrows(IllegalArgumentException.class, () -> region.maxY(-1)); + assertThrows(IllegalArgumentException.class, () -> region.maxZ(-1)); + } + + @Test + void createEmpty() { + BlockRegion empty = new BlockRegion(); + + final ArrayList blockPositions = Lists.newArrayList(BlockRegions.iterable(empty)); + + assertFalse(empty.isValid(), "empty region should be invalid"); + assertEquals(Collections.emptyList(), blockPositions, "empty region should contain no block positions"); + } + + static Stream fromMinAndSizeArgs() { + return Stream.of( + Arguments.of(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i()), + Arguments.of(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(3, 3, 3)), + Arguments.of(new Vector3i(3, 4, 5), new Vector3i(8, 5, 2), new Vector3i(10, 8, 6)) + ); + } + + @ParameterizedTest + @MethodSource("fromMinAndSizeArgs") + public void createFromMinAndSize(Vector3i min, Vector3i size, Vector3i expectedMax) { + BlockRegion region = BlockRegions.createFromMinAndSize(min, size); + BlockRegion expected = new BlockRegion().setMin(min).setSize(size); + + assertEquals(min, region.getMin(new Vector3i())); + assertEquals(size, region.getSize(new Vector3i())); + assertEquals(expectedMax, region.getMax(new Vector3i())); + assertEquals(expected, region); + } + + @Test + public void createFromMinAndSizeInvalid() { + assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), + new Vector3i(-1, 1, 1))); + assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), + new Vector3i(1, -1, 1))); + assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), + new Vector3i(1, 1, -1))); + } + + private static Stream createFromMinAndMaxArgs() { + return Stream.of( + Arguments.of(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i()), + Arguments.of(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(3, 3, 3)), + Arguments.of(new Vector3i(3, 4, 5), new Vector3i(8, 5, 2), new Vector3i(10, 8, 6)) + ); + } + + @ParameterizedTest + @MethodSource("createFromMinAndMaxArgs") + public void createFromMinAndMax(Vector3i min, Vector3i expectedSize, Vector3i max) { + BlockRegion region = BlockRegions.createFromMinAndMax(min, max); + assertEquals(min, region.getMin(new Vector3i()), "min"); + assertEquals(max, region.getMax(new Vector3i()), "max"); + assertEquals(expectedSize, region.getSize(new Vector3i()), "size"); + } + + private static Stream createFromMinAndMaxInvalidArgs() { + return Stream.of( + Arguments.of(new Vector3i(1, 1, 1), new Vector3i(0, 0, 0)), + Arguments.of(new Vector3i(0, 1, 0), new Vector3i(1, 0, 1)) + ); + } + + @ParameterizedTest + @MethodSource("createFromMinAndMaxInvalidArgs") + public void createFromMinAndMaxInvalid(Vector3i min, Vector3i max) { + assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndMax(min, max)); + } + + private static Stream createEncompassingArgs() { + return Stream.of( + Arguments.of(new Vector3i(1, 1, 1), + Lists.newArrayList(new Vector3i(), new Vector3i())), + Arguments.of(new Vector3i(3, 3, 3), + Lists.newArrayList(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3))), + Arguments.of(new Vector3i(3, 3, 3), + Lists.newArrayList(new Vector3i(3, 3, 3), new Vector3i(1, 1, 1))), + Arguments.of(new Vector3i(2, 2, 2), + Lists.newArrayList(new Vector3i(0, 1, 0), new Vector3i(1, 0, 1))), + Arguments.of(new Vector3i(2, 3, 4), + Lists.newArrayList(new Vector3i(0, 1, 0), new Vector3i(1, 0, 1), new Vector3i(0, -1, 3))) + ); + } + + @ParameterizedTest + @MethodSource("createEncompassingArgs") + public void createEncompassing(Vector3i expectedSize, Collection positions) { + Vector3i min = positions.stream().reduce(new Vector3i(Integer.MAX_VALUE), Vector3i::min); + Vector3i max = positions.stream().reduce(new Vector3i(Integer.MIN_VALUE), Vector3i::max); + + BlockRegion region = BlockRegions.encompassing(positions); + assertEquals(min, region.getMin(new Vector3i()), "min of " + region); + assertEquals(max, region.getMax(new Vector3i()), "max of " + region); + assertEquals(expectedSize, region.getSize(new Vector3i()), "size of " + region); + } + + @Test + public void testRegionInvalidIfMaxLessThanMin() { + assertThrows(IllegalArgumentException.class, + () -> BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(-1, 0, 0))); + } + + @Test + public void testIterateRegion() { + Vector3i min = new Vector3i(2, 5, 7); + Vector3i max = new Vector3i(10, 11, 12); + BlockRegion region = BlockRegions.createFromMinAndMax(min, max); + + Set expected = Sets.newHashSet(); + for (int x = min.x; x <= max.x; ++x) { + for (int y = min.y; y <= max.y; ++y) { + for (int z = min.z; z <= max.z; ++z) { + expected.add(new Vector3i(x, y, z)); + } + } + } + + for (Vector3ic pos : BlockRegions.iterableInPlace(region)) { + assertTrue(expected.contains(pos), "unexpected position: " + pos); + expected.remove(pos); + } + + assertEquals(0, expected.size(), "All vectors provided"); + } + + @Test + public void testSimpleIntersect() { + BlockRegion region1 = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(32, 32, 32)); + BlockRegion region2 = BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(17, 17, 17)); + assertEquals(region2, new BlockRegion(region1).intersect(region2).get()); + } + + @Test + public void testNonTouchingIntersect() { + BlockRegion region1 = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(32, 32, 32)); + BlockRegion region2 = BlockRegions.createFromMinAndMax(new Vector3i(103, 103, 103), new Vector3i(170, 170, + 170)); + assertEquals(Optional.empty(), new BlockRegion(region1).intersect(region2)); + } + + @Test + public void testEncompasses() { + BlockRegion region = new BlockRegion().union(new Vector3i()).setSize(new Vector3i(1, 1, 1)); + assertTrue(region.containsBlock(0, 0, 0)); + + assertFalse(region.containsBlock(1, 0, 0)); + assertFalse(region.containsBlock(1, 0, 1)); + assertFalse(region.containsBlock(0, 0, 1)); + assertFalse(region.containsBlock(-1, 0, -1)); + assertFalse(region.containsBlock(-1, 0, 0)); + assertFalse(region.containsBlock(-1, 0, -1)); + assertFalse(region.containsBlock(0, 0, -1)); + + assertFalse(region.containsBlock(1, 1, 0)); + assertFalse(region.containsBlock(1, 1, 1)); + assertFalse(region.containsBlock(0, 1, 1)); + assertFalse(region.containsBlock(-1, 1, -1)); + assertFalse(region.containsBlock(-1, 1, 0)); + assertFalse(region.containsBlock(-1, 1, -1)); + assertFalse(region.containsBlock(0, 1, -1)); + + assertFalse(region.containsBlock(1, -1, 0)); + assertFalse(region.containsBlock(1, -1, 1)); + assertFalse(region.containsBlock(0, -1, 1)); + assertFalse(region.containsBlock(-1, -1, -1)); + assertFalse(region.containsBlock(-1, -1, 0)); + assertFalse(region.containsBlock(-1, -1, -1)); + assertFalse(region.containsBlock(0, -1, -1)); + } + + private static Stream testCenterArgs() { + return Stream.of( + Arguments.of( + new BlockRegion(), + new Vector3f(Float.NaN) + ), + // creating from min and max + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), + new Vector3f(0f, 0f, 0f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)), + new Vector3f(.5f, .5f, .5f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(1, 1, 1)), + new Vector3f(0f, 0f, 0f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(2, 2, 2)), + new Vector3f(1f, 1f, 1f) + ), + // creating from center and extents + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)), + new Vector3f(0f, 0f, 0f) + ), + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0.5f, 0.5f, 0.5f), new Vector3f(0.5f, + 0.5f, 0.5f)), + new Vector3f(.5f, .5f, .5f) + ), + Arguments.of( + BlockRegions.createFromCenterAndExtents(new Vector3f(0.49f, 0.49f, 0.49f), new Vector3f(0.5f, + 0.5f, 0.5f)), + new Vector3f(0f, 0f, 0f) + ) + + ); + } + + @ParameterizedTest + @MethodSource("testCenterArgs") + public void testCenter(BlockRegion region, Vector3fc expectedCenter) { + assertEquals(expectedCenter, region.center(new Vector3f())); + } + + // -- contains ---------------------------------------------------------------------------------------------------// + + static Stream containsPointArgs() { + return Stream.of( + // positive cases + Arguments.of(new Vector3f(1.0f, 1.0f, 1.0f), true), + Arguments.of(new Vector3f(1.2f, 0f, 0f), true), + Arguments.of(new Vector3f(0f, 1.2f, 0f), true), + Arguments.of(new Vector3f(0f, 1.2f, 1.2f), true), + Arguments.of(new Vector3f(1.2f, 1.2f, 0f), true), + Arguments.of(new Vector3f(1.2f, 1.2f, 1.2f), true), + // negative cases + Arguments.of(new Vector3f(1.2f, 0f, -1.2f), false), + Arguments.of(new Vector3f(0f, 1.2f, -1.2f), false), + Arguments.of(new Vector3f(1.2f, 1.2f, -1.2f), false), + Arguments.of(new Vector3f(-1.2f, 0f, 0f), false), + Arguments.of(new Vector3f(-1.2f, 0f, 1.2f), false), + Arguments.of(new Vector3f(-1.2f, 0f, -1.2f), false), + Arguments.of(new Vector3f(0f, -1.2f, 0f), false), + Arguments.of(new Vector3f(0f, -1.2f, 1.2f), false), + Arguments.of(new Vector3f(0f, -1.2f, -1.2f), false), + Arguments.of(new Vector3f(-1.2f, 1.2f, 0f), false), + Arguments.of(new Vector3f(-1.2f, 1.2f, 1.2f), false), + Arguments.of(new Vector3f(-1.2f, 1.2f, -1.2f), false), + Arguments.of(new Vector3f(1.2f, -1.2f, 0f), false), + Arguments.of(new Vector3f(1.2f, -1.2f, 1.2f), false), + Arguments.of(new Vector3f(1.2f, -1.2f, -1.2f), false), + Arguments.of(new Vector3f(-1.2f, -1.2f, 0f), false), + Arguments.of(new Vector3f(-1.2f, -1.2f, 1.2f), false), + Arguments.of(new Vector3f(-1.2f, -1.2f, -1.2f), false) + ); + } + + @ParameterizedTest + @MethodSource("containsPointArgs") + public void containsPointPositive(Vector3f point, boolean shouldBeContained) { + BlockRegion region = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + + if (shouldBeContained) { + assertTrue(region.containsPoint(point), "point should be within region"); + } else { + assertFalse(region.containsPoint(point), "point should not be within region"); + } + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Test + public void testIntersectionPlane() { + BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + assertTrue(a.intersectsPlane(1, 1, 1, 1)); + assertFalse(a.intersectsPlane(1, 1, 1, 2)); + } + + @Test + public void testIntersectionBlockRegion() { + BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion b = BlockRegions.createFromMinAndMax(1, 1, 1, 4, 4, 4); + BlockRegion c = BlockRegions.createFromMinAndMax(3, 3, 3, 4, 4, 4); + + assertTrue(a.intersectsBlockRegion(b)); + assertFalse(a.intersectsBlockRegion(c)); + } + + + static Stream testIntersectionAABB() { + return Stream.of( + Arguments.of(new AABBf(-.5f, -.5f, -.5f, 1.5f, 1.5f, 1.5f), true), + Arguments.of(new AABBf(1.2f, 1.4999f, 1.2f, 2, 2, 2), true), + Arguments.of(new AABBf(1.2f, 1.5f, 1.2f, 2, 2, 2), true), + Arguments.of(new AABBf(1.2f, 1.50001f, 1.2f, 2, 2, 2), false), + Arguments.of(new AABBf(2, 2, 2, 3, 3, 3), false) + ); + } + + @ParameterizedTest + @MethodSource + public void testIntersectionAABB(AABBf aabb, boolean intersects) { + BlockRegion region = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + assertEquals(intersects, region.intersectsAABB(aabb)); + } + + @Test + public void testIntersectionSphere() { + BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + Spheref s1 = new Spheref(0, 0, 1, 2); + Spheref s2 = new Spheref(3, 3, 3, 1); + + assertTrue(a.intersectsSphere(s1)); + assertTrue(a.intersectsSphere(2, 2, 2, 1)); + assertFalse(a.intersectsSphere(s2)); + assertFalse(a.intersectsSphere(2, 2, 2, 0.25f)); + } + + @Test + public void testIntersectionRay() { + BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + Rayf r1 = new Rayf(0, 0, 3, 1, 1, -2); + Rayf r2 = new Rayf(0, 2, 2, 1, 0, 0); + + assertTrue(a.intersectsRay(r1)); + assertFalse(a.intersectsRay(r2)); + assertTrue(a.intersectsRay(1.2f, 0, 0, 1, 0, 0)); + assertFalse(a.intersectsRay(0, 0, 3, 1, 1, -1)); + } + + @Test + void testIntersectionLineSegment() { + BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + + //no intersection + assertEquals(a.intersectLineSegment(3f, 3f, 3f, 2f, 3f, 3f, new Vector2f()), -1); + LineSegmentf l1 = new LineSegmentf(3f, 2f, 3f, 2f, 3f, 2f); + assertEquals(a.intersectLineSegment(l1, new Vector2f()), -1); + + //one intersection + assertEquals(a.intersectLineSegment(1.2f, 1.2f, 1.2f, 1.6f, 1.6f, 1.6f, new Vector2f()), 1); + LineSegmentf l2 = new LineSegmentf(-0.6f, 0f, 0f, -0.2f, 1.2f, 0f); + assertEquals(a.intersectLineSegment(l2, new Vector2f()), 1); + + //two intersections + assertEquals(a.intersectLineSegment(1.2f, 1.2f, 2f, -0.6f, 0f, -0.2f, new Vector2f()), 2); + LineSegmentf l3 = new LineSegmentf(2f, 2f, 2f, -0.6f, -2f, 0f); + assertEquals(a.intersectLineSegment(l3, new Vector2f()), 2); + + //segment inside the BlocRegion + assertEquals(a.intersectLineSegment(0f, 1f, 1.2f, 1f, -0.2f, 0.2f, new Vector2f()), 3); + LineSegmentf l4 = new LineSegmentf(1f, 1f, 1.2f, -0.2f, 0f, 1f); + assertEquals(a.intersectLineSegment(l4, new Vector2f()), 3); + } + + static Stream getBoundsArgs() { + return Stream.of( + Arguments.of( + BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2, 3, 4)), + new AABBf(.5f, .5f, .5f, 2.5f, 3.5f, 4.5f) + ), + Arguments.of( + BlockRegions.createFromMinAndMax(-1, -1, -1, 1, 1, 1), + new AABBf(-1.5f, -1.5f, -1.5f, 1.5f, 1.5f, 1.5f) + ) + ); + } + + @ParameterizedTest + @MethodSource("getBoundsArgs") + void getBounds(BlockRegion region, AABBf bounds) { + assertEquals(bounds, region.getBounds(new AABBf())); + } + + static Stream copyRegionArgs() { + return Stream.of( + Arguments.of((Function) region -> new BlockRegion(region)), + Arguments.of((Function) region -> region.copy()), + Arguments.of((Function) region -> new BlockRegion(0, 0, 0).set(region)) + ); + } + + @ParameterizedTest + @MethodSource("copyRegionArgs") + void copyRegion(Function copyFn) { + BlockRegion original = BlockRegions.encompassing(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); + + BlockRegion source = BlockRegions.encompassing(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); + BlockRegion copy = copyFn.apply(source); + + assertEquals(original, copy); + + copy.setMax(2, 3, 4); + assertEquals(original, source, "source should not be modified"); + assertEquals(new Vector3i(2, 3, 4), copy.getMax(new Vector3i())); + } + + // -- extend -----------------------------------------------------------------------------------------------------// + + static Stream extendFloatArgs() { + return Stream.of( + Arguments.of(.1f, .1f, .1f, BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(3, 3, 3))), + Arguments.of(-.1f, -.1f, -.1f, BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2 + , 2, 2))), + Arguments.of(1f, 1f, 1f, BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(4, 4 + , 4))), + Arguments.of(-1f, -1f, -1f, BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2, 2 + , 2))), + Arguments.of(1.9f, 1.9f, 1.9f, BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), + new Vector3i(4, 4, 4))) + ); + } + + @ParameterizedTest + @MethodSource("extendFloatArgs") + void extendFloat(float x, float y, float z, BlockRegion expected) { + final BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(3, 3, 3)); + assertEquals(expected, region.copy().extend(x, y, z)); + } + + void extend(int x, int y, int z) { + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); + } + + static Stream extendInvalidArgs() { + return Stream.of( + Arguments.of(new Vector3i(-1, 0, 0)), + Arguments.of(new Vector3i(0, -1, 0)), + Arguments.of(new Vector3i(0, 0, -1)), + Arguments.of(new Vector3i(-1, -1, -1)) + ); + } + + @ParameterizedTest + @MethodSource("extendInvalidArgs") + void extendInvalid(Vector3i extents) { + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); + + assertThrows(IllegalArgumentException.class, () -> region.extend(extents)); + assertThrows(IllegalArgumentException.class, () -> region.extend(extents.x(), extents.y(), extents.z())); + } + + // -- union ------------------------------------------------------------------------------------------------------// + + static Stream unionArgs() { + return Stream.of( + Arguments.of(new Vector3i(-2, 4, -16), new Vector3i(4, 107, 0)), + Arguments.of(new Vector3i(4, 4, -16), new Vector3i(-2, 107, 0)), + Arguments.of(new Vector3i(-2, 107, -16), new Vector3i(4, 4, 0)), + Arguments.of(new Vector3i(-2, 4, 0), new Vector3i(4, 107, -16)), + Arguments.of(new Vector3i(4, 107, -16), new Vector3i(-2, 4, 0)), + Arguments.of(new Vector3i(4, 4, 0), new Vector3i(-2, 107, -16)), + Arguments.of(new Vector3i(-2, 107, 0), new Vector3i(4, 4, -16)), + Arguments.of(new Vector3i(4, 107, 0), new Vector3i(-2, 4, -16)) + ); + } + + @ParameterizedTest + @MethodSource("unionArgs") + public void union(Vector3i vec1, Vector3i vec2) { + BlockRegion expected = + BlockRegions.createFromMinAndMax(new Vector3i(-2, 4, -16), new Vector3i(4, 107, 0)); + + assertEquals(expected, new BlockRegion(vec1).union(vec2)); + assertEquals(expected, new BlockRegion(vec2).union(vec1)); + } + + static Stream unionWithRegionArgs() { + return Stream.of( + Arguments.of( + new BlockRegion(0, 0, 0), + new BlockRegion(0, 0, 0), + new BlockRegion(0, 0, 0) + ), + Arguments.of( + new BlockRegion(-1, -1, -1, 1, 1, 1), + new BlockRegion(2, 2, 2, 3, 4, 5), + new BlockRegion(-1, -1, -1, 3, 4, 5) + ) + ); + } + + @ParameterizedTest + @MethodSource("unionWithRegionArgs") + public void unionWithRegion(BlockRegion a, BlockRegion b, BlockRegion expected) { + assertEquals(expected, a.copy().union(b)); + assertEquals(expected, b.copy().union(a)); + } + + @Test + public void unionWithBlockEntity() { + Vector3i pos = new Vector3i(1, 2, 3); + final EntityRef entity = new PojoEntityManager().create(new BlockComponent(new Block(), pos)); + + BlockRegion region = new BlockRegion().union(entity); + assertTrue(region.containsBlock(pos)); + assertEquals(Collections.singletonList(pos), Lists.newArrayList(BlockRegions.iterable(region))); + } + + @Test + public void unionWithNonBlockEntity() { + final EntityRef entity = new PojoEntityManager().create(); + BlockRegion region = new BlockRegion().union(entity); + assertFalse(region.isValid()); + } + + // -- translate --------------------------------------------------------------------------------------------------// + + @Test + public void translate() { + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); + Vector3i translation = new Vector3i(1, 2, 3); + + assertEquals(new BlockRegion(1, 2, 3, 2, 3, 4), region.copy().translate(translation)); + assertEquals(region, region.copy().translate(translation).translate(translation.negate(new Vector3i()))); + } +} diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index 35e1a5d49f6..1b3f551af50 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -92,18 +92,13 @@ public void tearDown() { private Future requestCreatingOrLoadingArea(Vector3i chunkPosition, int radius) { Future chunkFuture = chunkProvider.createOrLoadChunk(chunkPosition); - BlockRegion extentsRegion = new BlockRegion( + BlockRegion extentsRegion = BlockRegions.createFromMinAndMax( chunkPosition.x - radius, chunkPosition.y - radius, chunkPosition.z - radius, chunkPosition.x + radius, chunkPosition.y + radius, chunkPosition.z + radius); - - BlockRegion subtract = new BlockRegion( // remove center. we takes future for it already. - chunkPosition.x, chunkPosition.y, chunkPosition.z, - chunkPosition.x, chunkPosition.y, chunkPosition.z); - BlockRegions.iterableInPlace(extentsRegion).iterator() .forEachRemaining(pos -> { - if (!pos.equals(JomlUtil.from(chunkPosition))) { + if (!pos.equals(JomlUtil.from(chunkPosition))) { // remove center. we takes future for it already. chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); } }); diff --git a/engine/src/main/java/org/terasology/math/ChunkMath.java b/engine/src/main/java/org/terasology/math/ChunkMath.java index dbac38fbddd..2d7026f8052 100644 --- a/engine/src/main/java/org/terasology/math/ChunkMath.java +++ b/engine/src/main/java/org/terasology/math/ChunkMath.java @@ -22,6 +22,7 @@ import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; import org.terasology.world.chunks.ChunkConstants; import java.math.RoundingMode; @@ -491,7 +492,7 @@ public static BlockRegion getChunkRegionAroundWorldPos(Vector3ic pos, int extent org.joml.Vector3i temp = new org.joml.Vector3i(); org.joml.Vector3i minChunk = calcChunkPos(temp.set(pos).add(-extent, -extent, -extent), new org.joml.Vector3i()); org.joml.Vector3i maxChunk = calcChunkPos(temp.set(pos).add(extent, extent, extent), new org.joml.Vector3i()); - return new BlockRegion(minChunk, maxChunk); + return BlockRegions.createFromMinAndMax(minChunk, maxChunk); } diff --git a/engine/src/main/java/org/terasology/math/JomlUtil.java b/engine/src/main/java/org/terasology/math/JomlUtil.java index 3be42d095e2..306ee81661b 100644 --- a/engine/src/main/java/org/terasology/math/JomlUtil.java +++ b/engine/src/main/java/org/terasology/math/JomlUtil.java @@ -44,6 +44,7 @@ import org.terasology.math.geom.Vector3f; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; import java.util.Map; import java.util.stream.Collectors; @@ -194,7 +195,7 @@ public static BlockRegion from(Region3i aabb) { if (aabb == null) { return null; } - return new BlockRegion(aabb.minX(), aabb.minY(), aabb.minZ(), aabb.maxX(), aabb.maxY(), aabb.maxZ()); + return BlockRegions.createFromMinAndMax(aabb.minX(), aabb.minY(), aabb.minZ(), aabb.maxX(), aabb.maxY(), aabb.maxZ()); } diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java index edaf1e47c2d..2080b2a5c2b 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java @@ -11,6 +11,7 @@ import org.terasology.persistence.typeHandling.PersistedDataSerializer; import org.terasology.persistence.typeHandling.TypeHandler; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegions; import java.util.Map; import java.util.Optional; @@ -26,8 +27,8 @@ public BlockRegionTypeHandler() { @Override protected PersistedData serializeNonNull(BlockRegion value, PersistedDataSerializer serializer) { Map map = Maps.newLinkedHashMap(); - map.put(MIN_FIELD, serializer.serialize(value.getMinX(), value.getMinY(), value.getMinZ())); - map.put(MAX_FIELD, serializer.serialize(value.getMaxX(), value.getMaxY(), value.getMaxZ())); + map.put(MIN_FIELD, serializer.serialize(value.minX(), value.minY(), value.minZ())); + map.put(MAX_FIELD, serializer.serialize(value.maxX(), value.maxY(), value.maxZ())); return serializer.serialize(map); } @@ -38,15 +39,22 @@ public Optional deserialize(PersistedData data) { PersistedDataArray minDataArr = map.get(MIN_FIELD).getAsArray(); TIntList minArr = minDataArr.getAsIntegerArray(); - if(map.has(SIZE_FIELD)) { + if (map.has(SIZE_FIELD)) { PersistedDataArray sizedataArray = map.get(SIZE_FIELD).getAsArray(); TIntList sizeArr = sizedataArray.getAsIntegerArray(); - return Optional.of(new BlockRegion(minArr.get(0), minArr.get(1), minArr.get(2), minArr.get(0) + sizeArr.get(0) - 1, minArr.get(1) + sizeArr.get(1) - 1, minArr.get(2) + sizeArr.get(2) - 1)); + return Optional.of( + BlockRegions.createFromMinAndMax( + minArr.get(0), minArr.get(1), minArr.get(2), + minArr.get(0) + sizeArr.get(0) - 1, minArr.get(1) + sizeArr.get(1) - 1, + minArr.get(2) + sizeArr.get(2) - 1)); } PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); TIntList maxArr = maxDataArr.getAsIntegerArray(); - return Optional.of(new BlockRegion(minArr.get(0), minArr.get(1), minArr.get(2), maxArr.get(0), maxArr.get(1), maxArr.get(2))); + return Optional.of( + BlockRegions.createFromMinAndMax( + minArr.get(0), minArr.get(1), minArr.get(2), + maxArr.get(0), maxArr.get(1), maxArr.get(2))); } return Optional.empty(); } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegion.java b/engine/src/main/java/org/terasology/world/block/BlockRegion.java index b5014b98634..e3c243d45a3 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegion.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegion.java @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block; +import com.google.common.base.Preconditions; import org.joml.AABBf; -import org.joml.AABBi; import org.joml.Intersectionf; import org.joml.LineSegmentf; import org.joml.Math; @@ -19,129 +19,205 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; +import java.util.Optional; + /** - * is a bounded box describing blocks contained within. A {@link BlockRegion} is described and backed by an {@link - * AABBi} + * A bounded, axis-aligned volume in space denoting a collection of blocks contained within. */ public class BlockRegion { /** - * AABB region that backs a BlockRegion + * The x coordinate of the minimum corner. + */ + private int minX = Integer.MAX_VALUE; + /** + * The y coordinate of the minimum corner. + */ + private int minY = Integer.MAX_VALUE; + /** + * The z coordinate of the minimum corner. + */ + private int minZ = Integer.MAX_VALUE; + /** + * The x coordinate of the maximum corner. */ - public final AABBi aabb = new AABBi(); + private int maxX = Integer.MIN_VALUE; + /** + * The y coordinate of the maximum corner. + */ + private int maxY = Integer.MIN_VALUE; + /** + * The z coordinate of the maximum corner. + */ + private int maxZ = Integer.MIN_VALUE; - public BlockRegion() { - } + // -- CONSTRUCTORS -----------------------------------------------------------------------------------------------// - public BlockRegion(BlockRegion source) { - aabb.set(source.aabb); + /** + * Creates an empty block region with invalid minimum/maximum corners. + *

+ * {@link #isValid()} will return {@code false} for an empty block region created via this constructor. + */ + @Deprecated + BlockRegion() { } - public BlockRegion(AABBi source) { - aabb.set(source); + BlockRegion(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + Preconditions.checkArgument(minX <= maxX); + Preconditions.checkArgument(minY <= maxY); + Preconditions.checkArgument(minZ <= maxZ); + + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; } - /** - * Deprecated in favor of {@link org.terasology.world.block.BlockRegions#createFromMinAndMax(Vector3ic, Vector3ic)} - */ - @Deprecated - public BlockRegion(Vector3ic min, Vector3ic max) { + BlockRegion(Vector3ic min, Vector3ic max) { this(min.x(), min.y(), min.z(), max.x(), max.y(), max.z()); } - /** - * Deprecated in favor of {@link org.terasology.world.block.BlockRegions#createFromMinAndMax(Vector3ic, Vector3ic)} - */ - @Deprecated - public BlockRegion(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - this.setMin(minX, minY, minZ).setMax(maxX, maxY, maxZ); + BlockRegion(int x, int y, int z) { + this(x, y, z, x, y, z); } + BlockRegion(Vector3ic block) { + this(block.x(), block.y(), block.z()); + } /** - * get the minimum block coordinate + * Create a new copy of the given block region {@code source}. * - * @param dest will hold the result - * @return dest + * @param source the block region to copy. */ - public Vector3i getMin(Vector3i dest) { - return dest.set(aabb.minX, aabb.minY, aabb.minZ); + public BlockRegion(BlockRegion source) { + this.set(source); } + // -- GETTERS & SETTERS ------------------------------------------------------------------------------------------// + /** - * get the maximum block coordinate + * set source to current region * - * @param dest will hold the result - * @return dest + * @param source the source region + * @return this */ - public Vector3i getMax(Vector3i dest) { - return dest.set(aabb.maxX - 1, aabb.maxY - 1, aabb.maxZ - 1); + public BlockRegion set(BlockRegion source) { + this.minX = source.minX; + this.minY = source.minY; + this.minZ = source.minZ; + + this.maxX = source.maxX; + this.maxY = source.maxY; + this.maxZ = source.maxZ; + return this; } + public BlockRegion copy() { + return new BlockRegion(this); + } + + // -- min --------------------------------------------------------------------------------------------------------// + /** - * the maximum coordinate of the second block x - * - * @return the minimum coordinate x + * The x-coordinate of the minimum corner */ - public int getMaxX() { - return this.aabb.maxX - 1; + public int minX() { + return this.minX; } /** - * the maximum coordinate of the second block y + * the minimum coordinate of the first block x * - * @return the minimum coordinate y + * @return the minimum coordinate x + * @deprecated use {@link #minX()} */ - public int getMaxY() { - return this.aabb.maxY - 1; + @Deprecated + public int getMinX() { + return this.minX; } /** - * the maximum coordinate of the second block z + * set the minimum coordinate of the first block x * - * @return the minimum coordinate z + * @return the minX */ - public int getMaxZ() { - return this.aabb.maxZ - 1; + public BlockRegion minX(int x) { + Preconditions.checkArgument(x <= this.maxX || this.maxX == Integer.MIN_VALUE); + this.minX = x; + return this; } /** - * the minimum coordinate of the first block x - * - * @return the minimum coordinate x + * The y-coordinate of the minimum corner */ - public int getMinX() { - return this.aabb.minX; + public int minY() { + return this.minY; } /** * the minimum coordinate of the first block y * * @return the minimum coordinate y + * @deprecated use {@link #minY()} */ + @Deprecated public int getMinY() { - return this.aabb.minY; + return this.minY; + } + + /** + * set the minimum coordinate of the first block y + * + * @return the minY + */ + public BlockRegion minY(int y) { + Preconditions.checkArgument(y <= this.maxY || this.maxY == Integer.MIN_VALUE); + this.minY = y; + return this; + } + + /** + * The z-coordinate of the minimum corner + */ + public int minZ() { + return this.minZ; } /** * the minimum coordinate of the first block z * * @return the minimum coordinate z + * @deprecated use {@link #minZ()} */ + @Deprecated public int getMinZ() { - return this.aabb.minZ; + return this.minZ; } /** - * set source to current region - * @param source the source region - * @return this + * set the minimum coordinate of the first block z + * + * @return the minZ */ - public BlockRegion set(BlockRegion source) { - this.aabb.set(source.aabb); + public BlockRegion minZ(int z) { + Preconditions.checkArgument(z <= this.maxZ || this.maxZ == Integer.MIN_VALUE); + this.minZ = z; return this; } + /** + * Get the block coordinate minimum corner. + * + * @param dest will hold the result + */ + public Vector3i getMin(Vector3i dest) { + return dest.set(minX, minY, minZ); + } + /** * Sets the minimum coordinate of the first block for this {@link BlockRegion} * @@ -149,187 +225,178 @@ public BlockRegion set(BlockRegion source) { * @return this */ public BlockRegion setMin(Vector3ic min) { - this.aabb.setMin(min); - return this; + return this.setMin(min.x(), min.y(), min.z()); } /** - * Sets the maximum coordinate of the second block for this {@link BlockRegion} + * sets the minimum block for this {@link BlockRegion} * - * @param max the second coordinate of the second block + * @param minX the x coordinate of the first block + * @param minY the y coordinate of the first block + * @param minZ the z coordinate of the first block * @return this */ - public BlockRegion setMax(Vector3ic max) { - this.setMax(max.x(), max.y(), max.z()); + public BlockRegion setMin(int minX, int minY, int minZ) { + Preconditions.checkArgument(minX <= this.maxX || this.maxX == Integer.MIN_VALUE); + Preconditions.checkArgument(minY <= this.maxY || this.maxX == Integer.MIN_VALUE); + Preconditions.checkArgument(minZ <= this.maxZ || this.maxX == Integer.MIN_VALUE); + this.minX = minX; + this.minY = minY; + this.minZ = minZ; return this; } + // -- max --------------------------------------------------------------------------------------------------------// + /** - * sets the maximum block for this {@link BlockRegion} + * The x-coordinate of the maximum corner + */ + public int maxX() { + return this.maxX; + } + + /** + * the maximum coordinate of the second block x * - * @param maxX the x coordinate of the first block - * @param maxY the y coordinate of the first block - * @param maxZ the z coordinate of the first block - * @return this + * @return the minimum coordinate x + * @deprecated use {@link #maxX()} */ - public BlockRegion setMax(int maxX, int maxY, int maxZ) { - this.aabb.setMax(maxX + 1, maxY + 1, maxZ + 1); - return this; + @Deprecated + public int getMaxX() { + return this.maxX; } /** - * sets the minimum block for this {@link BlockRegion} + * set the maximum coordinate of the second block x * - * @param minX the x coordinate of the first block - * @param minY the y coordinate of the first block - * @param minZ the z coordinate of the first block - * @return this + * @return the minX */ - public BlockRegion setMin(int minX, int minY, int minZ) { - aabb.setMin(minX, minY, minZ); + public BlockRegion maxX(int x) { + Preconditions.checkArgument(x >= this.minX || this.minX == Integer.MAX_VALUE); + this.maxX = x; return this; } /** - * Set this to the union of this and the given {@link EntityRef} associated with a block - * p. - * - * @param blockRef entityRef that describes a block - * @param dest will hold the result - * @return dest + * The y-coordinate of the maximum corner */ - public BlockRegion union(EntityRef blockRef, BlockRegion dest) { - BlockComponent component = blockRef.getComponent(BlockComponent.class); - if (component != null) { - return this.union(component.position.x(), component.position.y(), component.position.z(), dest); - } - return dest; + public int maxY() { + return this.maxY; } /** - * Set this to the union of this and the given block p. + * the maximum coordinate of the second block y * - * @param p the position of the block - * @return this + * @return the minimum coordinate y + * @deprecated use {@link #maxY()} */ - public BlockRegion union(Vector3ic p) { - return union(p.x(), p.y(), p.z(), this); + @Deprecated + public int getMaxY() { + return this.maxY; } /** - * Compute the union of this and the given block (x, y, z) and stores the result in - * dest + * set the maximum coordinate of the second block y * - * @param x the x coordinate of the block - * @param y the y coordinate of the block - * @param z the z coordinate of the block - * @param dest will hold the result - * @return dest + * @return the minY */ - public BlockRegion union(int x, int y, int z, BlockRegion dest) { - // a block is (x,y,z) and (x + 1, y + 1, z + 1) - dest.aabb.minX = Math.min(this.aabb.minX, x); - dest.aabb.minY = Math.min(this.aabb.minY, y); - dest.aabb.minZ = Math.min(this.aabb.minZ, z); - dest.aabb.maxX = Math.max(this.aabb.maxX, (x + 1)); - dest.aabb.maxY = Math.max(this.aabb.maxY, (y + 1)); - dest.aabb.maxZ = Math.max(this.aabb.maxZ, (z + 1)); - return dest; + public BlockRegion maxY(int y) { + Preconditions.checkArgument(y >= this.minY || this.minY == Integer.MAX_VALUE); + this.maxY = y; + return this; + } + + /** + * The z-coordinate of the maximum corner + */ + public int maxZ() { + return this.maxZ; } /** - * Compute the union of this and the given block (x, y, z) and store the result in - * dest. + * the maximum coordinate of the second block z * - * @param pos the position of the block - * @param dest will hold the result - * @return dest + * @return the minimum coordinate z + * @deprecated use {@link #maxZ()} */ - public BlockRegion union(Vector3ic pos, BlockRegion dest) { - return this.union(pos.x(), pos.y(), pos.z(), dest); + @Deprecated + public int getMaxZ() { + return this.maxZ; } /** - * Set this to the union of this and other. + * set the maximum coordinate of the second block z * - * @param other {@link BlockRegion} - * @return this + * @return the minZ */ - public BlockRegion union(BlockRegion other) { - return this.union(other.aabb); + public BlockRegion maxZ(int z) { + Preconditions.checkArgument(z >= this.minZ || this.minZ == Integer.MAX_VALUE); + this.maxZ = z; + return this; } /** - * Set this to the union of this and other. + * Get the block coordinate of the maximum corner. * - * @param other {@link AABBi} * @param dest will hold the result - * @return dest */ - public BlockRegion union(AABBi other, BlockRegion dest) { - dest.union(other); - return dest; + public Vector3i getMax(Vector3i dest) { + return dest.set(maxX, maxY, maxZ); } /** - * Set this to the union of this and other. + * Sets the maximum coordinate of the second block for this {@link BlockRegion} * - * @param other the other {@link AABBi} + * @param max the second coordinate of the second block * @return this */ - public BlockRegion union(AABBi other) { - this.aabb.union(other); - return this; + public BlockRegion setMax(Vector3ic max) { + return this.setMax(max.x(), max.y(), max.z()); } /** - * Ensure that the minimum coordinates are strictly less than or equal to the maximum coordinates by swapping them - * if necessary. + * sets the maximum block for this {@link BlockRegion} * + * @param maxX the x coordinate of the first block + * @param maxY the y coordinate of the first block + * @param maxZ the z coordinate of the first block * @return this */ - public BlockRegion correctBounds() { - // NOTE: this is basically the same as AABBi#correctBounds, but adjusted for off-by-one semantics here in - // BlockRegion for the max value. - int tmp; - if (this.aabb.minX > this.aabb.maxX - 1) { - tmp = this.aabb.minX; - this.aabb.minX = this.aabb.maxX - 1; - this.aabb.maxX = tmp + 1; - } - if (this.aabb.minY > this.aabb.maxY - 1) { - tmp = this.aabb.minY; - this.aabb.minY = this.aabb.maxY - 1; - this.aabb.maxY = tmp + 1; - } - if (this.aabb.minZ > this.aabb.maxZ - 1) { - tmp = this.aabb.minZ; - this.aabb.minZ = this.aabb.maxZ - 1; - this.aabb.maxZ = tmp + 1; - } + public BlockRegion setMax(int maxX, int maxY, int maxZ) { + Preconditions.checkArgument(maxX >= this.minX || this.minX == Integer.MAX_VALUE); + Preconditions.checkArgument(maxY >= this.minY || this.minY == Integer.MAX_VALUE); + Preconditions.checkArgument(maxZ >= this.minZ || this.minZ == Integer.MAX_VALUE); + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; return this; } + // -- size -------------------------------------------------------------------------------------------------------// + /** - * set the size of the block region from minimum. + * Set the size of the block region from minimum the minimum corner. * - * @param x the x coordinate to set the size - * @param y the y coordinate to set the size - * @param z the z coordinate to set the size - * @return this + * @param x the x coordinate to set the size; must be > 0 + * @param y the y coordinate to set the size; must be > 0 + * @param z the z coordinate to set the size; must be > 0 + * @return this after modification */ public BlockRegion setSize(int x, int y, int z) { - this.aabb.maxX = this.aabb.minX + x; - this.aabb.maxY = this.aabb.minY + y; - this.aabb.maxZ = this.aabb.minZ + z; + Preconditions.checkArgument(x > 0); + Preconditions.checkArgument(y > 0); + Preconditions.checkArgument(z > 0); + this.maxX = this.minX + x - 1; + this.maxY = this.minY + y - 1; + this.maxZ = this.minZ + z - 1; return this; } /** - * set the size of the block region from minimum. + * Set the size of the block region from minimum the minimum corner. * - * @param size the size to set the {@link BlockRegion} - * @return this + * @param size the size to set; all dimensions must be > 0 + * @return this after modification */ public BlockRegion setSize(Vector3ic size) { return setSize(size.x(), size.y(), size.z()); @@ -342,8 +409,7 @@ public BlockRegion setSize(Vector3ic size) { * @return dest */ public Vector3i getSize(Vector3i dest) { - return dest.set(this.aabb.maxX - this.aabb.minX, this.aabb.maxY - this.aabb.minY, - this.aabb.maxZ - this.aabb.minZ); + return dest.set(sizeX(), sizeY(), sizeZ()); } /** @@ -351,8 +417,8 @@ public Vector3i getSize(Vector3i dest) { * * @return number of blocks in the X axis */ - public int getSizeX() { - return this.aabb.maxX - this.aabb.minX; + public int sizeX() { + return this.maxX - this.minX + 1; } /** @@ -360,8 +426,8 @@ public int getSizeX() { * * @return number of blocks in the Y axis */ - public int getSizeY() { - return this.aabb.maxY - this.aabb.minY; + public int sizeY() { + return this.maxY - this.minY + 1; } /** @@ -369,46 +435,199 @@ public int getSizeY() { * * @return number of blocks in the Z axis */ - public int getSizeZ() { - return this.aabb.maxZ - this.aabb.minZ; + public int sizeZ() { + return this.maxZ - this.minZ + 1; + } + + // -- world ------------------------------------------------------------------------------------------------------// + + //TODO: 1.9.26 has a constant interface for aabbf + public AABBf getBounds(AABBf dest) { + dest.minX = minX - .5f; + dest.minY = minY - .5f; + dest.minZ = minZ - .5f; + + dest.maxX = maxX + .5f; + dest.maxY = maxY + .5f; + dest.maxZ = maxZ + .5f; + + return dest; + } + + /** + * The center of the region if the region is valid, {@link Float#NaN} in all dimensions otherwise. + * + * @param dest will hold the result + * @return dest + */ + public Vector3f center(Vector3f dest) { + if (!this.isValid()) { + return dest.set(Float.NaN); + } + return dest.set( + (this.minX - .5f) + ((this.maxX - this.minX + 1.0f) / 2.0f), + (this.minY - .5f) + ((this.maxY - this.minY + 1.0f) / 2.0f), + (this.minZ - .5f) + ((this.maxZ - this.minZ + 1.0f) / 2.0f) + ); + } + + // -- IN-PLACE MUTATION ------------------------------------------------------------------------------------------// + + /** + * Compute the union of this and the given block (x, y, z). + * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + */ + public BlockRegion union(int x, int y, int z) { + this.minX = Math.min(this.minX, x); + this.minY = Math.min(this.minY, y); + this.minZ = Math.min(this.minZ, z); + + this.maxX = Math.max(this.maxX, x); + this.maxY = Math.max(this.maxY, y); + this.maxZ = Math.max(this.maxZ, z); + return this; + } + + /** + * Set this to the union of this and the given block pos. + * + * @param pos the position of the block + * @return this + */ + public BlockRegion union(Vector3ic pos) { + return union(pos.x(), pos.y(), pos.z()); + } + + /** + * Set this to the union of this and other. + * + * @param other {@link BlockRegion} + * @return this + */ + public BlockRegion union(BlockRegion other) { + return this.union(other.minX, other.minY, other.minZ).union(other.maxX, other.maxY, other.maxZ); } + /** + * Set this to the union of this and the given {@link EntityRef} associated with a block + * p. + * + * @param blockRef entityRef that describes a block + */ + public BlockRegion union(EntityRef blockRef) { + BlockComponent component = blockRef.getComponent(BlockComponent.class); + if (component != null) { + return this.union(component.position.x(), component.position.y(), component.position.z()); + } + return this; + } + + // ---------------------------------------------------------------------------------------------------------------// + + /** + * calculate the BlockRegion that is intersected between another region + * + * @param other the other BlockRegion + */ + public Optional intersect(BlockRegion other) { + this.minX = Math.max(minX, other.minX); + this.minY = Math.max(minY, other.minY); + this.minZ = Math.max(minZ, other.minZ); + + this.maxX = Math.min(maxX, other.maxX); + this.maxY = Math.min(maxY, other.maxY); + this.maxZ = Math.min(maxZ, other.maxZ); + + if (this.isValid()) { + return Optional.of(this); + } else { + return Optional.empty(); + } + } + + // ---------------------------------------------------------------------------------------------------------------// + /** * Translate this by the given vector xyz. * * @param x the x coordinate to translate by * @param y the y coordinate to translate by * @param z the z coordinate to translate by - * @return this */ public BlockRegion translate(int x, int y, int z) { - aabb.translate(x, y, z); + this.minX = this.minX + x; + this.minY = this.minY + y; + this.minZ = this.minZ + z; + this.maxX = this.maxX + x; + this.maxY = this.maxY + y; + this.maxZ = this.maxZ + z; return this; } /** - * Translate this by the given vector xyz. + * Translate this by the given vector vec. * - * @param xyz the vector to translate by - * @param dest will hold the result - * @return dest + * @param vec the vector to translate by + * @return this */ - public BlockRegion translate(Vector3ic xyz, BlockRegion dest) { - aabb.translate(xyz, dest.aabb); - return dest; + public BlockRegion translate(Vector3ic vec) { + return translate(vec.x(), vec.y(), vec.z()); } + // ---------------------------------------------------------------------------------------------------------------// + /** - * Translate this by the given vector xyz. + * Adds extend for each face of a BlockRegion * - * @param xyz the vector to translate by - * @return this + * @param extentX the x coordinate to grow the extents + * @param extentY the y coordinate to grow the extents + * @param extentZ the z coordinate to grow the extents */ - public BlockRegion translate(Vector3ic xyz) { - this.aabb.translate(xyz); + public BlockRegion extend(int extentX, int extentY, int extentZ) { + Preconditions.checkArgument(sizeX() + 2 * extentX > 0); + Preconditions.checkArgument(sizeY() + 2 * extentY > 0); + Preconditions.checkArgument(sizeZ() + 2 * extentZ > 0); + this.minX = this.minX - extentX; + this.minY = this.minY - extentY; + this.minZ = this.minZ - extentZ; + + this.maxX = this.maxX + extentX; + this.maxY = this.maxY + extentY; + this.maxZ = this.maxZ + extentZ; + return this; } + /** + * Adds extend for each face of a BlockRegion. + * + * @param extents the coordinates to grow the extents + * @return this + */ + public BlockRegion extend(Vector3ic extents) { + return extend(extents.x(), extents.y(), extents.z()); + } + + /** + * Adds extend for each face of a BlockRegion. + * + * @param extentX the x coordinate to grow the extents + * @param extentY the y coordinate to grow the extents + * @param extentZ the z coordinate to grow the extents + * @return dest + */ + public BlockRegion extend(float extentX, float extentY, float extentZ) { + return extend( + Math.roundUsing(extentX, RoundingMode.FLOOR), + Math.roundUsing(extentY, RoundingMode.FLOOR), + Math.roundUsing(extentZ, RoundingMode.FLOOR)); + } + + // ---------------------------------------------------------------------------------------------------------------// + /** * Apply the given {@link Matrix4fc#isAffine() affine} transformation to this {@link BlockRegion}. *

@@ -417,9 +636,38 @@ public BlockRegion translate(Vector3ic xyz) { * @param m the affine transformation matrix * @return this */ - public BlockRegion transform(Matrix4fc m) { - this.aabb.transform(m); - return this; + public BlockRegion transform(Matrix4fc m, BlockRegion dest) { + float dx = maxX - minX; + float dy = maxY - minY; + float dz = maxZ - minZ; + float minx = Float.POSITIVE_INFINITY; + float miny = Float.POSITIVE_INFINITY; + float minz = Float.POSITIVE_INFINITY; + float maxx = Float.NEGATIVE_INFINITY; + float maxy = Float.NEGATIVE_INFINITY; + float maxz = Float.NEGATIVE_INFINITY; + for (int i = 0; i < 8; i++) { + float x = minX + (i & 1) * dx; + float y = minY + (i >> 1 & 1) * dy; + float z = minZ + (i >> 2 & 1) * dz; + float tx = m.m00() * x + m.m10() * y + m.m20() * z + m.m30(); + float ty = m.m01() * x + m.m11() * y + m.m21() * z + m.m31(); + float tz = m.m02() * x + m.m12() * y + m.m22() * z + m.m32(); + minx = Math.min(tx, minx); + miny = Math.min(ty, miny); + minz = Math.min(tz, minz); + maxx = Math.max(tx, maxx); + maxy = Math.max(ty, maxy); + maxz = Math.max(tz, maxz); + } + dest.minX = Math.roundUsing(minx, RoundingMode.FLOOR); + dest.minY = Math.roundUsing(miny, RoundingMode.FLOOR); + dest.minZ = Math.roundUsing(minz, RoundingMode.FLOOR); + dest.maxX = Math.roundUsing(maxx, RoundingMode.CEILING); + dest.maxY = Math.roundUsing(maxy, RoundingMode.CEILING); + dest.maxZ = Math.roundUsing(maxz, RoundingMode.CEILING); + + return dest; } /** @@ -430,36 +678,32 @@ public BlockRegion transform(Matrix4fc m) { * @param m the affine transformation matrix * @return this */ - public BlockRegion transform(Matrix4fc m, BlockRegion dest) { - this.aabb.transform(m, dest.aabb); - return dest; + public BlockRegion transform(Matrix4fc m) { + return transform(m, this); } + // -- CHECKS -----------------------------------------------------------------------------------------------------// + /** - * Test whether the block (x, y, z) lies inside this BlockRegion. + * Check whether this BlockRegion represents a valid BlockRegion. * - * @param pos the coordinates of the block - * @return true iff the given point lies inside this AABB; false otherwise + * @return true iff this BlockRegion is valid; false otherwise */ - public boolean containsBlock(Vector3ic pos) { - return containsBlock(pos.x(), pos.y(), pos.z()); + public boolean isValid() { + return minX <= maxX && minY <= maxY && minZ <= maxZ; } + + // -- contains ---------------------------------------------------------------------------------------------------// + /** - * The center of the region if the region is valid, {@link Float#NaN} in all dimensions otherwise. + * Test whether the block (x, y, z) lies inside this BlockRegion. * - * @param dest will hold the result - * @return dest + * @param pos the coordinates of the block + * @return true iff the given point lies inside this AABB; false otherwise */ - public Vector3f center(Vector3f dest) { - if (!this.isValid()) { - return dest.set(Float.NaN); - } - return dest.set( - aabb.minX + ((aabb.maxX - aabb.minX) / 2.0f), - aabb.minY + ((aabb.maxY - aabb.minY) / 2.0f), - aabb.minZ + ((aabb.maxZ - aabb.minZ) / 2.0f) - ); + public boolean containsBlock(Vector3ic pos) { + return containsBlock(pos.x(), pos.y(), pos.z()); } /** @@ -471,7 +715,7 @@ public Vector3f center(Vector3f dest) { * @return true iff the given point lies inside this AABB; false otherwise */ public boolean containsBlock(int x, int y, int z) { - return x >= aabb.minX && y >= aabb.minY && z >= aabb.minZ && x < aabb.maxX && y < aabb.maxY && z < aabb.maxZ; + return x >= minX && y >= minY && z >= minZ && x <= maxX && y <= maxY && z <= maxZ; } /** @@ -483,29 +727,12 @@ public boolean containsBlock(int x, int y, int z) { * @return true iff the given point lies inside this BlockRegion; false otherwise */ public boolean containsPoint(float x, float y, float z) { - return this.aabb.containsPoint(x, y, z); - } - - /** - * Test whether the point (x, y, z) lies inside this AABB. - * - * @param x the x coordinate of the point - * @param y the y coordinate of the point - * @param z the z coordinate of the point - * @return true iff the given point lies inside this AABB; false otherwise - */ - public boolean containsPoint(int x, int y, int z) { - return this.aabb.containsPoint(x, y, z); - } - - /** - * Test whether the given point lies inside this AABB. - * - * @param point the coordinates of the point - * @return true iff the given point lies inside this AABB; false otherwise - */ - public boolean containsPoint(Vector3ic point) { - return this.aabb.containsPoint(point); + return x >= (this.minX - .5f) + && y >= (this.minY - .5f) + && z >= (this.minZ - .5f) + && x <= (this.maxX + .5f) + && y <= (this.maxY + .5f) + && z <= (this.maxZ + .5f); } /** @@ -515,9 +742,11 @@ public boolean containsPoint(Vector3ic point) { * @return true iff the given point lies inside this AABB; false otherwise */ public boolean containsPoint(Vector3fc point) { - return this.aabb.containsPoint(point); + return this.containsPoint(point.x(), point.y(), point.z()); } + // -- intersects -------------------------------------------------------------------------------------------------// + /** * Test whether the plane given via its plane equation a*x + b*y + c*z + d = 0 intersects this AABB. *

@@ -532,7 +761,13 @@ public boolean containsPoint(Vector3fc point) { * @return true iff the plane intersects this AABB; false otherwise */ public boolean intersectsPlane(float a, float b, float c, float d) { - return this.aabb.intersectsPlane(a, b, c, d); + return Intersectionf.testAabPlane( + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, a, b, c, d); } /** @@ -546,7 +781,18 @@ public boolean intersectsPlane(float a, float b, float c, float d) { * @return true iff the plane intersects this AABB; false otherwise */ public boolean intersectsPlane(Planef plane) { - return this.aabb.intersectsPlane(plane); + return Intersectionf.testAabPlane( + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, + plane.a, + plane.b, + plane.c, + plane.d + ); } /** @@ -556,17 +802,8 @@ public boolean intersectsPlane(Planef plane) { * @return true iff both AABBs intersect; false otherwise */ public boolean intersectsBlockRegion(BlockRegion other) { - return this.aabb.intersectsAABB(other.aabb); - } - - /** - * Test whether this and other intersect. - * - * @param other the other AABB - * @return true iff both AABBs intersect; false otherwise - */ - public boolean intersectsAABB(AABBi other) { - return this.aabb.intersectsAABB(other); + return this.maxX >= other.minX && this.maxY >= other.minY && this.maxZ >= other.minZ && + this.minX <= other.maxX && this.minY <= other.maxY && this.minZ <= other.maxZ; } /** @@ -576,7 +813,12 @@ public boolean intersectsAABB(AABBi other) { * @return true iff both AABBs intersect; false otherwise */ public boolean intersectsAABB(AABBf other) { - return this.aabb.intersectsAABB(other); + return Intersectionf.testAabAab( + this.minX - .5f, this.minY - .5f, this.minZ - .5f, + this.maxX + .5f, this.maxY + .5f, this.maxZ + .5f, + other.minX, other.minY, other.minZ, + other.maxX, other.maxY, other.maxZ + ); } /** @@ -593,8 +835,18 @@ public boolean intersectsAABB(AABBf other) { * @return true iff this AABB and the sphere intersect; false otherwise */ public boolean intersectsSphere(float centerX, float centerY, float centerZ, float radiusSquared) { - return Intersectionf.testAabSphere(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ, centerX, - centerY, centerZ, radiusSquared); + return Intersectionf.testAabSphere( + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, + centerX, + centerY, + centerZ, + radiusSquared + ); } /** @@ -607,7 +859,18 @@ public boolean intersectsSphere(float centerX, float centerY, float centerZ, flo * @return true iff this AABB and the sphere intersect; false otherwise */ public boolean intersectsSphere(Spheref sphere) { - return Intersectionf.testAabSphere(aabb, sphere); + return Intersectionf.testAabSphere( + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, + sphere.x, + sphere.y, + sphere.z, + sphere.r * sphere.r + ); } /** @@ -627,8 +890,15 @@ public boolean intersectsSphere(Spheref sphere) { * @return true if this AABB and the ray intersect; false otherwise */ public boolean intersectsRay(float originX, float originY, float originZ, float dirX, float dirY, float dirZ) { - return Intersectionf.testRayAab(originX, originY, originZ, dirX, dirY, dirZ, aabb.minX, aabb.minY, aabb.minZ, - aabb.maxX, aabb.maxY, aabb.maxZ); + return Intersectionf.testRayAab( + originX, originY, originZ, dirX, dirY, dirZ, + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f + ); } /** @@ -642,7 +912,15 @@ public boolean intersectsRay(float originX, float originY, float originZ, float * @return true if this AABB and the ray intersect; false otherwise */ public boolean intersectsRay(Rayf ray) { - return Intersectionf.testRayAab(ray, aabb); + return Intersectionf.testRayAab( + ray.oX, ray.oY, ray.oZ, ray.dX, ray.dY, ray.dZ, + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f + ); } /** @@ -670,8 +948,14 @@ public boolean intersectsRay(Rayf ray) { * an edge or a side of this AABB */ public int intersectLineSegment(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z, Vector2f result) { - return Intersectionf.intersectLineSegmentAab(p0X, p0Y, p0Z, p1X, p1Y, p1Z, aabb.minX, aabb.minY, aabb.minZ, - aabb.maxX, aabb.maxY, aabb.maxZ, result); + return Intersectionf.intersectLineSegmentAab(p0X, p0Y, p0Z, p1X, p1Y, p1Z, + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, result); + } /** @@ -694,134 +978,49 @@ public int intersectLineSegment(float p0X, float p0Y, float p0Z, float p1X, floa * an edge or a side of this AABB */ public int intersectLineSegment(LineSegmentf lineSegment, Vector2f result) { - return Intersectionf.intersectLineSegmentAab(lineSegment, aabb, result); - } - - /** - * Check whether this BlockRegion represents a valid BlockRegion. - * - * @return true iff this BlockRegion is valid; false otherwise - */ - public boolean isValid() { - return aabb.isValid(); - } - - /** - * calculate the BlockRegion that is intersected between another region - * - * @param other the other BlockRegion - * @param dest holds the result - * @return dest - */ - public BlockRegion intersection(BlockRegion other, BlockRegion dest) { - this.aabb.intersection(other.aabb, dest.aabb); - return dest; - } - - /** - * Adds extend for each face of a BlockRegion. - * - * @param extent extents to grow each face - * @param dest holds the result - * @return dest - */ - public BlockRegion addExtents(int extent, BlockRegion dest) { - return addExtents(extent, extent, extent, dest); - } - - /** - * Adds extend for each face of a BlockRegion. - * - * @param extentX the x coordinate to grow the extents - * @param extentY the y coordinate to grow the extents - * @param extentZ the z coordinate to grow the extents - * @return this - */ - public BlockRegion addExtents(int extentX, int extentY, int extentZ) { - return addExtents(extentX, extentY, extentZ, this); - } - - /** - * Adds extend for each face of a BlockRegion. - * - * @param extents extents to grow each face - * @param dest holds the result - * @return dest - */ - public BlockRegion addExtents(Vector3ic extents, BlockRegion dest) { - return addExtents(extents.x(), extents.y(), extents.z(), dest); - } - - /** - * Adds extend for each face of a BlockRegion. - * - * @param extents the coordinates to grow the extents - * @return this - */ - public BlockRegion addExtents(Vector3ic extents) { - return addExtents(extents.x(), extents.y(), extents.z(), this); - } - - /** - * Adds extend for each face of a BlockRegion - * - * @param extentX the x coordinate to grow the extents - * @param extentY the y coordinate to grow the extents - * @param extentZ the z coordinate to grow the extents - * @param dest will hold the result - * @return dest - */ - public BlockRegion addExtents(int extentX, int extentY, int extentZ, BlockRegion dest) { - dest.aabb.minX = this.aabb.minX - extentX; - dest.aabb.minY = this.aabb.minY - extentY; - dest.aabb.minZ = this.aabb.minZ - extentZ; - - dest.aabb.maxX = this.aabb.maxX + extentX; - dest.aabb.maxY = this.aabb.maxY + extentY; - dest.aabb.maxZ = this.aabb.maxZ + extentZ; - return dest; - } - - /** - * Adds extend for each face of a BlockRegion. - * - * @param extentX the x coordinate to grow the extents - * @param extentY the y coordinate to grow the extents - * @param extentZ the z coordinate to grow the extents - * @param dest will hold the result - * @return dest - */ - public BlockRegion addExtents(float extentX, float extentY, float extentZ, BlockRegion dest) { - dest.aabb.minX = Math.roundUsing(this.aabb.minX - extentX, RoundingMode.FLOOR); - dest.aabb.minY = Math.roundUsing(this.aabb.minY - extentY, RoundingMode.FLOOR); - dest.aabb.minZ = Math.roundUsing(this.aabb.minZ - extentZ, RoundingMode.FLOOR); - - dest.aabb.maxX = Math.roundUsing(this.aabb.maxX + extentX, RoundingMode.CEILING); - dest.aabb.maxY = Math.roundUsing(this.aabb.maxY + extentY, RoundingMode.CEILING); - dest.aabb.maxZ = Math.roundUsing(this.aabb.maxZ + extentZ, RoundingMode.CEILING); - return dest; + return Intersectionf.intersectLineSegmentAab( + lineSegment.aX, lineSegment.aY, lineSegment.aZ, lineSegment.bX, lineSegment.bY, lineSegment.bZ, + minX - .5f, + minY - .5f, + minZ - .5f, + maxX + .5f, + maxY + .5f, + maxZ + .5f, result); } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (o == null || getClass() != o.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } - BlockRegion region = (BlockRegion) o; - return aabb.equals(region.aabb); + BlockRegion region = (BlockRegion) obj; + return minX == region.minX + && minY == region.minY + && minZ == region.minZ + && maxX == region.maxX + && maxY == region.maxY + && maxZ == region.maxZ; } @Override public int hashCode() { - return aabb.hashCode(); + final int prime = 31; + int result = 1; + result = prime * result + minX; + result = prime * result + minY; + result = prime * result + minZ; + result = prime * result + maxX; + result = prime * result + maxY; + result = prime * result + maxZ; + return result; } @Override public String toString() { - return "(" + this.aabb.minX + " " + this.aabb.minY + " " + this.aabb.minZ + ") < " + - "(" + (this.aabb.maxX - 1) + " " + (this.aabb.maxY - 1) + " " + (this.aabb.maxZ - 1) + ")"; + return "(" + this.minX + " " + this.minY + " " + this.minZ + ") < " + + "(" + (this.maxX - 1) + " " + (this.maxY - 1) + " " + (this.maxZ - 1) + ")"; } } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java b/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java index eff783d4852..be2977b4007 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java @@ -19,16 +19,16 @@ public class BlockRegionIterable implements Iterable { public Iterator iterator() { return new Iterator() { private Vector3i current = null; - private final Vector3i next = new Vector3i(region.getMinX(), region.getMinY(), region.getMinZ()); + private final Vector3i next = region.getMin(new Vector3i()); public boolean findNext() { if (current.equals(next)) { next.z++; - if (next.z > region.getMaxZ()) { - next.z = region.getMinZ(); + if (next.z > region.maxZ()) { + next.z = region.minZ(); next.y++; - if (next.y > region.getMaxY()) { - next.y = region.getMinY(); + if (next.y > region.maxY()) { + next.y = region.minY(); next.x++; } } @@ -39,6 +39,9 @@ public boolean findNext() { @Override public boolean hasNext() { + if (!region.isValid()) { + return false; + } if (current == null) { return true; } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegions.java b/engine/src/main/java/org/terasology/world/block/BlockRegions.java index 85d6e0af2c6..fa6faaa8502 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegions.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegions.java @@ -10,7 +10,10 @@ import org.joml.Vector3ic; import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; public final class BlockRegions { private BlockRegions() { @@ -28,7 +31,7 @@ private BlockRegions() { * @return new block region */ public static BlockRegion createFromMinAndMax(Vector3ic min, Vector3ic max) { - return new BlockRegion().setMin(min).setMax(max); + return new BlockRegion(min, max); } /** @@ -43,7 +46,7 @@ public static BlockRegion createFromMinAndMax(Vector3ic min, Vector3ic max) { * @return new block region */ public static BlockRegion createFromMinAndMax(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - return new BlockRegion().setMin(minX, minY, minZ).setMax(maxX, maxY, maxZ); + return new BlockRegion(minX, minY, minZ, maxX, maxY, maxZ); } /** @@ -53,7 +56,7 @@ public static BlockRegion createFromMinAndMax(int minX, int minY, int minZ, int * @return new block region */ public static BlockRegion createFromCenterAndExtents(Vector3ic center, Vector3ic extents) { - return new BlockRegion().union(center).addExtents(extents); + return new BlockRegion(center).extend(extents); } /** @@ -68,9 +71,7 @@ public static BlockRegion createFromCenterAndExtents(Vector3fc center, Vector3fc Vector3f min = center.sub(extents, new Vector3f()); Vector3f max = center.add(extents, new Vector3f()); - return new BlockRegion() - .setMin(new Vector3i(min, RoundingMode.CEILING)) - .setMax(new Vector3i(max, RoundingMode.FLOOR)); + return new BlockRegion(new Vector3i(min, RoundingMode.CEILING), new Vector3i(max, RoundingMode.FLOOR)); } /** @@ -80,16 +81,16 @@ public static BlockRegion createFromCenterAndExtents(Vector3fc center, Vector3fc * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region * will have a size of 0 along that dimension. *

- * Consider using {@link #encompassing(Vector3ic...)} as an alternative. + * Consider using {@link #encompassing(Vector3ic, Vector3ic...)} as an alternative. * * @return new block region */ public static BlockRegion createFromMinAndSize(Vector3ic min, Vector3ic size) { - return new BlockRegion().setMin(min).setMax( - min.x() + size.x() - 1, - min.y() + size.y() - 1, - min.z() + size.z() - 1 - ); + return new BlockRegion(min).setSize(size); + } + + public static BlockRegion encompassing(Stream positions) { + return positions.reduce(new BlockRegion(), BlockRegion::union, BlockRegion::union); } /** @@ -98,8 +99,16 @@ public static BlockRegion createFromMinAndSize(Vector3ic min, Vector3ic size) { * @param positions the positions that must be contained in the resulting block region * @return a new block region containing all given positions */ - public static BlockRegion encompassing(Vector3ic... positions) { - return Arrays.stream(positions).reduce(new BlockRegion(), BlockRegion::union, BlockRegion::union); + public static BlockRegion encompassing(Vector3ic first, Vector3ic... positions) { + return encompassing(Stream.concat(Stream.of(first), Arrays.stream(positions))); + } + + public static BlockRegion encompassing(Iterable positions) { + return encompassing(StreamSupport.stream(positions.spliterator(), false)); + } + + public static BlockRegion encompassing(Collection positions) { + return encompassing(positions.stream()); } /** diff --git a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java index 7b3510fc122..8a3c33d2f03 100644 --- a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java +++ b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionComponent.java @@ -8,15 +8,19 @@ import org.terasology.world.block.BlockRegion; /** + * */ public class BlockRegionComponent implements Component { + /** + * May be null. + */ @Replicate - public BlockRegion region = new BlockRegion(); + public BlockRegion region; public BlockRegionComponent() { } public BlockRegionComponent(BlockRegion region) { - this.region.set(region); + this.region = new BlockRegion(region); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java index 758e87c13e9..e0d66b08854 100644 --- a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java @@ -24,7 +24,6 @@ import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegionIterable; import org.terasology.world.block.BlockRegions; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.LitChunk; @@ -34,8 +33,7 @@ import java.util.Set; /** - * Batch propagator that works on a set of changed blocks - * Works for a single given propagation ruleset + * Batch propagator that works on a set of changed blocks Works for a single given propagation ruleset */ public class StandardBatchPropagator implements BatchPropagator { @@ -122,7 +120,8 @@ private void reviewChange(BlockChange blockChange) { /* Process propagation out to other blocks */ for (Side side : Side.getAllSides()) { - PropagationComparison comparison = rules.comparePropagation(blockChange.getTo(), blockChange.getFrom(), side); + PropagationComparison comparison = rules.comparePropagation(blockChange.getTo(), blockChange.getFrom(), + side); if (comparison.isRestricting() && existingValue > 0) { /* If the propagation of the new value is going to be lower/reduced */ @@ -153,7 +152,7 @@ private void reviewChange(BlockChange blockChange) { /** * Reset a position to only it's fixed values * - * @param pos The position to reset + * @param pos The position to reset * @param oldValue The value present before reset */ private void purge(Vector3i pos, byte oldValue) { @@ -188,8 +187,7 @@ private void purge(Vector3i pos, byte oldValue) { } /** - * Process all reducing propagation requests - * This is done from the largest value through the smallest. + * Process all reducing propagation requests This is done from the largest value through the smallest. */ private void processReduction() { for (int depth = 0; depth < rules.getMaxValue(); depth++) { @@ -208,8 +206,7 @@ private void processReduction() { } /** - * Process all increasing propagation requests - * This is done from the strongest through to the weakest. + * Process all increasing propagation requests This is done from the strongest through to the weakest. */ private void processIncrease() { for (int depth = 0; depth < rules.getMaxValue() - 1; depth++) { @@ -231,10 +228,10 @@ private void processIncrease() { /** * Propagates a value from a position out into all adjacent blocks. *

- * If the value spreading into a block is larger than the current value there, set it and queue it for propagating again - * If the value is smaller than the current value, do nothing + * If the value spreading into a block is larger than the current value there, set it and queue it for propagating + * again If the value is smaller than the current value, do nothing * - * @param pos The initial position + * @param pos The initial position * @param value The value to propagate */ private void push(Vector3i pos, byte value) { @@ -258,13 +255,12 @@ private void push(Vector3i pos, byte value) { } /** - * Set the value at a position to a new value. - * This should be larger than the prior value + * Set the value at a position to a new value. This should be larger than the prior value *

* Queues up this new higher value to be propagated out * * @param position The position to set at - * @param value The value to set the position to + * @param value The value to set the position to */ private void increase(Vector3i position, byte value) { world.setValueAt(position, value); @@ -284,11 +280,10 @@ private void reduce(Vector3i position, byte oldValue) { } /** - * Queues up a propagation from a given position. - * Propagation is placed into a queue for the given level. + * Queues up a propagation from a given position. Propagation is placed into a queue for the given level. * * @param position The position to propagate form - * @param value The value to propagate out + * @param value The value to propagate out */ private void queueSpreadValue(Vector3i position, byte value) { if (value > 1) { @@ -309,17 +304,18 @@ private void cleanUp() { public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boolean propagateExternal) { IndexProvider indexProvider = createIndexProvider(side); - BlockRegion edgeRegion = ChunkMath.getEdgeRegion( - new BlockRegion(0,0,0,0,0,0).setSize(JomlUtil.from(ChunkConstants.CHUNK_SIZE)), side, new BlockRegion()); + BlockRegion edgeRegion = BlockRegions.createFromMinAndSize(new org.joml.Vector3i(0, 0, 0), JomlUtil.from(ChunkConstants.CHUNK_SIZE)); + ChunkMath.getEdgeRegion(edgeRegion, side, edgeRegion); - int edgeSize = edgeRegion.getSizeX() * edgeRegion.getSizeY() * edgeRegion.getSizeZ(); + int edgeSize = edgeRegion.sizeX() * edgeRegion.sizeY() * edgeRegion.sizeZ(); int[] depth = new int[edgeSize]; propagateSide(chunk, adjChunk, side, indexProvider, edgeRegion, depth); propagateDepth(adjChunk, side, propagateExternal, indexProvider, edgeRegion, depth); } - private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExternal, IndexProvider indexProvider, BlockRegion edgeRegion, int[] depths) { + private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExternal, IndexProvider indexProvider, + BlockRegion edgeRegion, int[] depths) { Vector3i adjPos = new Vector3i(); int[] adjDepth = new int[depths.length]; @@ -354,7 +350,8 @@ private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExter } } - private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, IndexProvider indexProvider, BlockRegion edgeRegion, int[] depths) { + private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, IndexProvider indexProvider, + BlockRegion edgeRegion, int[] depths) { Vector3i adjPos = new Vector3i(); for (int x = edgeRegion.getMinX(); x <= edgeRegion.getMaxX(); ++x) { for (int y = edgeRegion.getMinY(); y <= edgeRegion.getMaxY(); ++y) { From 7e379c9e9c7dea5924e09b26cd603ec74ffdb52e Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 21 Dec 2020 19:26:17 -0800 Subject: [PATCH 035/259] refactor(gradle): repositories are a property of Publishing, not a specific publication. --- config/gradle/publish.gradle | 80 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/config/gradle/publish.gradle b/config/gradle/publish.gradle index 20c5b212bfa..26daf51f10f 100644 --- a/config/gradle/publish.gradle +++ b/config/gradle/publish.gradle @@ -8,6 +8,46 @@ apply from: "$rootDir/config/gradle/common.gradle" apply plugin: 'maven-publish' publishing { + repositories { + maven { + name = 'TerasologyOrg' + + if (rootProject.hasProperty("publishRepo")) { + // This first option is good for local testing, you can set a full explicit target repo in gradle.properties + url = "http://artifactory.terasology.org/artifactory/$publishRepo" + allowInsecureProtocol true // 😱 + logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) + } else { + // Support override from the environment to use a different target publish org + String deducedPublishRepo = System.getenv()["PUBLISH_ORG"] + if (deducedPublishRepo == null || deducedPublishRepo == "") { + // If not then default + deducedPublishRepo = "terasology" + } + + if (project.version.toString().endsWith("-SNAPSHOT")) { + deducedPublishRepo += "-snapshot-local" + } else { + deducedPublishRepo += "-release-local" + } + + logger.info("The final deduced publish repo is {}", deducedPublishRepo) + url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" + allowInsecureProtocol true + } + + if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { + credentials { + username = "$mavenUser" + password = "$mavenPass" + } + authentication { + basic(BasicAuthentication) + } + } + } + } + publications { "$project.name"(MavenPublication) { // Without this we get a .pom with no dependencies @@ -15,46 +55,6 @@ publishing { artifact source: sourceJar, classifier: 'sources' artifact source: javadocJar, classifier: 'javadoc' - - repositories { - maven { - name = 'TerasologyOrg' - - if (rootProject.hasProperty("publishRepo")) { - // This first option is good for local testing, you can set a full explicit target repo in gradle.properties - url = "http://artifactory.terasology.org/artifactory/$publishRepo" - allowInsecureProtocol true // 😱 - logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) - } else { - // Support override from the environment to use a different target publish org - String deducedPublishRepo = System.getenv()["PUBLISH_ORG"] - if (deducedPublishRepo == null || deducedPublishRepo == "") { - // If not then default - deducedPublishRepo = "terasology" - } - - if (project.version.toString().endsWith("-SNAPSHOT")) { - deducedPublishRepo += "-snapshot-local" - } else { - deducedPublishRepo += "-release-local" - } - - logger.info("The final deduced publish repo is {}", deducedPublishRepo) - url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" - allowInsecureProtocol true - } - - if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { - credentials { - username = "$mavenUser" - password = "$mavenPass" - } - authentication { - basic(BasicAuthentication) - } - } - } - } } } } From 0d635e23bd63f747831418859605dd630d5aa742 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 21 Dec 2020 19:31:06 -0800 Subject: [PATCH 036/259] fix(gradle): delay making decisions based on project version until it is configured. --- config/gradle/publish.gradle | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/config/gradle/publish.gradle b/config/gradle/publish.gradle index 26daf51f10f..31aeb166936 100644 --- a/config/gradle/publish.gradle +++ b/config/gradle/publish.gradle @@ -25,15 +25,22 @@ publishing { deducedPublishRepo = "terasology" } - if (project.version.toString().endsWith("-SNAPSHOT")) { - deducedPublishRepo += "-snapshot-local" - } else { - deducedPublishRepo += "-release-local" - } + afterEvaluate { + // depends on project.version, so must be delayed until project is configured + if (!project.version || project.version == "unspecified") { + throw new GradleException("Project ${project} does not have a version set yet: ${project.version}") + } + + if (project.version.toString().endsWith("-SNAPSHOT")) { + deducedPublishRepo += "-snapshot-local" + } else { + deducedPublishRepo += "-release-local" + } - logger.info("The final deduced publish repo is {}", deducedPublishRepo) - url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" - allowInsecureProtocol true + logger.info("The final deduced publish repo is {}", deducedPublishRepo) + url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" + allowInsecureProtocol true + } } if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { From 5cfb0c66f5457d16cffe1246a697314ccc1cd328 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 21 Dec 2020 19:53:35 -0800 Subject: [PATCH 037/259] fix(gradle): engine-test does not need to make its own -SNAPSHOT determinations This was overlooked in #4039, and as a result engine-test was making versions like `4.2.0-SNAPSHOT-SNAPSHOT` --- engine-tests/build.gradle | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/engine-tests/build.gradle b/engine-tests/build.gradle index 27a24f20a31..084c36955e6 100644 --- a/engine-tests/build.gradle +++ b/engine-tests/build.gradle @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 // Engine tests are split out due to otherwise quirky project dependency issues with module tests extending engine tests @@ -46,11 +33,6 @@ def moduleConfig = slurper.parseText(moduleFile.text) // Gradle uses the magic version variable when creating the jar name (unless explicitly set differently) version = moduleConfig.version -// The only case in which we make non-snapshots is when BRANCH_NAME exists and contains "master" - otherwise snapshots -if (env.BRANCH_NAME == null || !env.BRANCH_NAME.equals("master")) { - version += "-SNAPSHOT" -} - // Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor group = 'org.terasology.engine' From bad53694cc2295377f78103b34ad410bada4f912 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Thu, 24 Dec 2020 23:24:17 +0100 Subject: [PATCH 038/259] refactor!(BlockRegion): full API overhaul (#4326) * doc(BlockRegion): full docs for immutable interface BlockRegionc * test(BlockRegion): more test cases for BlockRegion * refactor!(BlockRegion): name all `contains` check consistently * feat(BlockRegion): expose INVALID region to be used for reduction * feat(BlockRegion): add immutable interface `BlockRegionc` * refactor(BlockRegion): implement BlockRegion in terms of BlockRegionc * refactor!(BlockRegion): remove BlockRegions and BlockRegionIterable Co-authored-by: Michael Pollind --- .../org/terasology/math/ChunkMathTest.java | 8 +- .../mathTypes/BlockRegionTypeHandlerTest.java | 3 +- .../world/block/BlockRegionIterableTest.java | 84 -- .../world/block/BlockRegionTest.java | 351 +++--- .../LocalChunkProviderTest.java | 14 +- .../java/org/terasology/math/ChunkMath.java | 118 +- .../java/org/terasology/math/JomlUtil.java | 4 +- .../mathTypes/BlockRegionTypeHandler.java | 8 +- .../terasology/world/block/BlockRegion.java | 1034 +++++------------ .../world/block/BlockRegionIterable.java | 73 -- .../terasology/world/block/BlockRegionc.java | 786 +++++++++++++ .../terasology/world/block/BlockRegions.java | 154 --- .../world/block/entity/BlockEntitySystem.java | 3 +- .../block/regions/BlockRegionSystem.java | 3 +- .../LocalChunkProvider.java | 12 +- .../RemoteChunkProvider.java | 7 +- .../internal/EntityAwareWorldProvider.java | 13 +- .../propagation/StandardBatchPropagator.java | 15 +- 18 files changed, 1341 insertions(+), 1349 deletions(-) delete mode 100644 engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java delete mode 100644 engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java create mode 100644 engine/src/main/java/org/terasology/world/block/BlockRegionc.java delete mode 100644 engine/src/main/java/org/terasology/world/block/BlockRegions.java diff --git a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java index d50bfa04155..20c732e9a24 100644 --- a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java +++ b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java @@ -21,7 +21,7 @@ import org.terasology.context.internal.MockContext; import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; -import org.terasology.world.block.BlockRegions; +import org.terasology.world.block.BlockRegion; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -97,11 +97,11 @@ public void testCalcChunkPos() { @Test public void testChunkRegionAroundWorldPos() { assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 100), - BlockRegions.createFromMinAndMax(-4, -2, -4, 3, 1, 3)); + new BlockRegion(-4, -2, -4, 3, 1, 3)); assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(-30, -30, -30), 100), - BlockRegions.createFromMinAndMax(-5, -3, -5, 2, 1, 2)); + new BlockRegion(-5, -3, -5, 2, 1, 2)); assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 10), - BlockRegions.createFromMinAndMax(-1, -1, -1, 0, 0, 0)); + new BlockRegion(-1, -1, -1, 0, 0, 0)); } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java index b2bfeae63c6..4dd5e1e5a59 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java @@ -14,7 +14,6 @@ import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.persistence.typeHandling.gson.GsonBuilderFactory; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; public class BlockRegionTypeHandlerTest extends MathTypeAssert { public static class AABBBlockRegion1Test { @@ -31,7 +30,7 @@ public static class AABBBlockRegion1Test { @Test public void testSerializeBlockRegion() { AABBBlockRegion1Test aabb1 = new AABBBlockRegion1Test(); - aabb1.a1 = BlockRegions.createFromMinAndMax(5, 5, 5, 13, 12, 14); + aabb1.a1 = new BlockRegion(5, 5, 5, 13, 12, 14); aabb1.a2 = new AABBi(3, 5, 5, 22, 12, 14); JsonElement tree = gson.toJsonTree(aabb1); diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java deleted file mode 100644 index 8f1c15e97ee..00000000000 --- a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionIterableTest.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.world.block; - -import org.joml.Vector3i; -import org.joml.Vector3ic; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -public class BlockRegionIterableTest { - - @Test - public void testSingleBlockRegion() { - BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)); - Iterable iterable = BlockRegions.iterable(region); - - List actual = new ArrayList<>(); - for (Vector3ic vector3ic : iterable) { - actual.add(new Vector3i(vector3ic)); - } - - Assertions.assertEquals(1, actual.size()); - Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); - } - - @Test - public void testLineOfBlocksRegion() { - BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 1, 0)); - Iterable iterable = BlockRegions.iterable(region); - - List actual = new ArrayList<>(); - for (Vector3ic vector3ic : iterable) { - actual.add(new Vector3i(vector3ic)); - } - - Assertions.assertEquals(2, actual.size()); - Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); - } - - @Test - public void testPlaneOfBlocksRegion() { - BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 1, 1)); - Iterable iterable = BlockRegions.iterable(region); - - List actual = new ArrayList<>(); - for (Vector3ic vector3ic : iterable) { - actual.add(new Vector3i(vector3ic)); - } - - Assertions.assertEquals(4, actual.size()); - Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); - } - - @Test - public void testBoxOfBlocksRegion() { - BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)); - Iterable iterable = BlockRegions.iterable(region); - - List actual = new ArrayList<>(); - for (Vector3ic vector3ic : iterable) { - actual.add(new Vector3i(vector3ic)); - } - - Assertions.assertEquals(8, actual.size()); - Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); - } - - private List expectedPositions(BlockRegion region) { - List result = new ArrayList<>(region.sizeX() * region.sizeY() * region.sizeZ()); - for (int x = region.getMinX(); x <= region.getMaxX(); x++) { - for (int y = region.getMinY(); y <= region.getMaxY(); y++) { - for (int z = region.getMinZ(); z <= region.getMaxZ(); z++) { - result.add(new Vector3i(x, y, z)); - } - } - } - return result; - } -} diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java index 57245d503e7..dde835bfadd 100644 --- a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java @@ -14,16 +14,17 @@ import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.entitySystem.entity.internal.PojoEntityManager; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -34,34 +35,30 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -/** - * - */ public class BlockRegionTest { @Test void getMinMax() { final Vector3i min = new Vector3i(1, 2, 3); final Vector3i max = new Vector3i(7, 8, 9); - final BlockRegion region = - BlockRegions.createFromMinAndMax(min, max); + final BlockRegion region = new BlockRegion(min, max); assertEquals(min, region.getMin(new Vector3i())); assertEquals(max, region.getMax(new Vector3i())); - assertEquals(min.x, region.getMinX()); - assertEquals(region.getMinX(), region.minX()); - assertEquals(min.y, region.getMinY()); - assertEquals(region.getMinY(), region.minY()); - assertEquals(min.z, region.getMinZ()); - assertEquals(region.getMinZ(), region.minZ()); + assertEquals(min.x, region.minX()); + assertEquals(region.minX(), region.minX()); + assertEquals(min.y, region.minY()); + assertEquals(region.minY(), region.minY()); + assertEquals(min.z, region.minZ()); + assertEquals(region.minZ(), region.minZ()); - assertEquals(max.x, region.getMaxX()); - assertEquals(region.getMaxX(), region.maxX()); - assertEquals(max.y, region.getMaxY()); - assertEquals(region.getMaxY(), region.maxY()); - assertEquals(max.z, region.getMaxZ()); - assertEquals(region.getMaxZ(), region.maxZ()); + assertEquals(max.x, region.maxX()); + assertEquals(region.maxX(), region.maxX()); + assertEquals(max.y, region.maxY()); + assertEquals(region.maxY(), region.maxY()); + assertEquals(max.z, region.maxZ()); + assertEquals(region.maxZ(), region.maxZ()); } @Test @@ -89,11 +86,28 @@ void setMinMaxInvalid() { assertThrows(IllegalArgumentException.class, () -> region.maxZ(-1)); } + static Stream sizeArgs() { + return Stream.of( + Arguments.of(new BlockRegion(-10, -10, -10, -5, -5, -5), new Vector3i(6)), + Arguments.of(new BlockRegion(0, 0, 0, 0, 0, 0), new Vector3i(1)), + Arguments.of(new BlockRegion(0, 0, 0, 1, 2, 3), new Vector3i(2, 3, 4)), + Arguments.of(new BlockRegion(new Vector3i(-1), new Vector3i(1)), new Vector3i(3)) + ); + } + + @ParameterizedTest + @MethodSource("sizeArgs") + void size(BlockRegion region, Vector3i expected) { + assertEquals(expected, region.getSize(new Vector3i())); + } + + // -- creation --------------------------------------------------------------------------------------------------// + @Test void createEmpty() { - BlockRegion empty = new BlockRegion(); + BlockRegionc empty = BlockRegion.INVALID; - final ArrayList blockPositions = Lists.newArrayList(BlockRegions.iterable(empty)); + final ArrayList blockPositions = Lists.newArrayList(empty); assertFalse(empty.isValid(), "empty region should be invalid"); assertEquals(Collections.emptyList(), blockPositions, "empty region should contain no block positions"); @@ -109,27 +123,25 @@ static Stream fromMinAndSizeArgs() { @ParameterizedTest @MethodSource("fromMinAndSizeArgs") - public void createFromMinAndSize(Vector3i min, Vector3i size, Vector3i expectedMax) { - BlockRegion region = BlockRegions.createFromMinAndSize(min, size); - BlockRegion expected = new BlockRegion().setMin(min).setSize(size); + public void fromMinAndSize(Vector3i min, Vector3i size, Vector3i expectedMax) { + BlockRegion region = new BlockRegion(min).setSize(size); assertEquals(min, region.getMin(new Vector3i())); assertEquals(size, region.getSize(new Vector3i())); assertEquals(expectedMax, region.getMax(new Vector3i())); - assertEquals(expected, region); } @Test - public void createFromMinAndSizeInvalid() { - assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), - new Vector3i(-1, 1, 1))); - assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), - new Vector3i(1, -1, 1))); - assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndSize(new Vector3i(), - new Vector3i(1, 1, -1))); + public void fromMinAndSizeInvalid() { + assertThrows(IllegalArgumentException.class, + () -> new BlockRegion(new Vector3i()).setSize(new Vector3i(-1, 1, 1))); + assertThrows(IllegalArgumentException.class, + () -> new BlockRegion(new Vector3i()).setSize(new Vector3i(1, -1, 1))); + assertThrows(IllegalArgumentException.class, + () -> new BlockRegion(new Vector3i()).setSize(new Vector3i(1, 1, -1))); } - private static Stream createFromMinAndMaxArgs() { + private static Stream fromMinAndMaxArgs() { return Stream.of( Arguments.of(new Vector3i(), new Vector3i(1, 1, 1), new Vector3i()), Arguments.of(new Vector3i(1, 1, 1), new Vector3i(3, 3, 3), new Vector3i(3, 3, 3)), @@ -138,9 +150,9 @@ private static Stream createFromMinAndMaxArgs() { } @ParameterizedTest - @MethodSource("createFromMinAndMaxArgs") - public void createFromMinAndMax(Vector3i min, Vector3i expectedSize, Vector3i max) { - BlockRegion region = BlockRegions.createFromMinAndMax(min, max); + @MethodSource("fromMinAndMaxArgs") + public void fromMinAndMax(Vector3i min, Vector3i expectedSize, Vector3i max) { + BlockRegion region = new BlockRegion(min, max); assertEquals(min, region.getMin(new Vector3i()), "min"); assertEquals(max, region.getMax(new Vector3i()), "max"); assertEquals(expectedSize, region.getSize(new Vector3i()), "size"); @@ -149,14 +161,29 @@ public void createFromMinAndMax(Vector3i min, Vector3i expectedSize, Vector3i ma private static Stream createFromMinAndMaxInvalidArgs() { return Stream.of( Arguments.of(new Vector3i(1, 1, 1), new Vector3i(0, 0, 0)), - Arguments.of(new Vector3i(0, 1, 0), new Vector3i(1, 0, 1)) + Arguments.of(new Vector3i(0, 1, 0), new Vector3i(1, 0, 1)), + Arguments.of(new Vector3i(0, 0, 0), new Vector3i(-1, 0, 0)) ); } @ParameterizedTest @MethodSource("createFromMinAndMaxInvalidArgs") - public void createFromMinAndMaxInvalid(Vector3i min, Vector3i max) { - assertThrows(IllegalArgumentException.class, () -> BlockRegions.createFromMinAndMax(min, max)); + public void fromMinAndMaxInvalid(Vector3i min, Vector3i max) { + assertThrows(IllegalArgumentException.class, () -> new BlockRegion(min, max)); + } + + static Stream fromCenterAndExtentsInvalidArgs() { + return Stream.of( + Arguments.of(new Vector3i(-1, 1, 1)), + Arguments.of(new Vector3i(1, -1, 1)), + Arguments.of(new Vector3i(1, 1, -1)) + ); + } + + @ParameterizedTest + @MethodSource("fromCenterAndExtentsInvalidArgs") + public void fromCenterAndExtentsInvalid(Vector3i extents) { + assertThrows(IllegalArgumentException.class, () -> new BlockRegion(new Vector3i()).expand(extents)); } private static Stream createEncompassingArgs() { @@ -180,23 +207,20 @@ public void createEncompassing(Vector3i expectedSize, Collection posit Vector3i min = positions.stream().reduce(new Vector3i(Integer.MAX_VALUE), Vector3i::min); Vector3i max = positions.stream().reduce(new Vector3i(Integer.MIN_VALUE), Vector3i::max); - BlockRegion region = BlockRegions.encompassing(positions); + BlockRegion region = positions.stream().reduce(new BlockRegion(BlockRegion.INVALID), BlockRegion::union, + BlockRegion::union); assertEquals(min, region.getMin(new Vector3i()), "min of " + region); assertEquals(max, region.getMax(new Vector3i()), "max of " + region); assertEquals(expectedSize, region.getSize(new Vector3i()), "size of " + region); } - @Test - public void testRegionInvalidIfMaxLessThanMin() { - assertThrows(IllegalArgumentException.class, - () -> BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(-1, 0, 0))); - } + // -- iterable --------------------------------------------------------------------------------------------------// @Test public void testIterateRegion() { Vector3i min = new Vector3i(2, 5, 7); Vector3i max = new Vector3i(10, 11, 12); - BlockRegion region = BlockRegions.createFromMinAndMax(min, max); + BlockRegion region = new BlockRegion(min, max); Set expected = Sets.newHashSet(); for (int x = min.x; x <= max.x; ++x) { @@ -207,7 +231,7 @@ public void testIterateRegion() { } } - for (Vector3ic pos : BlockRegions.iterableInPlace(region)) { + for (Vector3ic pos : region) { assertTrue(expected.contains(pos), "unexpected position: " + pos); expected.remove(pos); } @@ -217,88 +241,76 @@ public void testIterateRegion() { @Test public void testSimpleIntersect() { - BlockRegion region1 = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(32, 32, 32)); - BlockRegion region2 = BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(17, 17, 17)); + BlockRegion region1 = new BlockRegion(new Vector3i(), new Vector3i(32, 32, 32)); + BlockRegion region2 = new BlockRegion(new Vector3i(1, 1, 1), new Vector3i(17, 17, 17)); assertEquals(region2, new BlockRegion(region1).intersect(region2).get()); } @Test public void testNonTouchingIntersect() { - BlockRegion region1 = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(32, 32, 32)); - BlockRegion region2 = BlockRegions.createFromMinAndMax(new Vector3i(103, 103, 103), new Vector3i(170, 170, - 170)); + BlockRegion region1 = new BlockRegion(new Vector3i(), new Vector3i(32, 32, 32)); + BlockRegion region2 = new BlockRegion(new Vector3i(103, 103, 103), new Vector3i(170, 170, 170)); assertEquals(Optional.empty(), new BlockRegion(region1).intersect(region2)); } @Test public void testEncompasses() { - BlockRegion region = new BlockRegion().union(new Vector3i()).setSize(new Vector3i(1, 1, 1)); - assertTrue(region.containsBlock(0, 0, 0)); - - assertFalse(region.containsBlock(1, 0, 0)); - assertFalse(region.containsBlock(1, 0, 1)); - assertFalse(region.containsBlock(0, 0, 1)); - assertFalse(region.containsBlock(-1, 0, -1)); - assertFalse(region.containsBlock(-1, 0, 0)); - assertFalse(region.containsBlock(-1, 0, -1)); - assertFalse(region.containsBlock(0, 0, -1)); - - assertFalse(region.containsBlock(1, 1, 0)); - assertFalse(region.containsBlock(1, 1, 1)); - assertFalse(region.containsBlock(0, 1, 1)); - assertFalse(region.containsBlock(-1, 1, -1)); - assertFalse(region.containsBlock(-1, 1, 0)); - assertFalse(region.containsBlock(-1, 1, -1)); - assertFalse(region.containsBlock(0, 1, -1)); - - assertFalse(region.containsBlock(1, -1, 0)); - assertFalse(region.containsBlock(1, -1, 1)); - assertFalse(region.containsBlock(0, -1, 1)); - assertFalse(region.containsBlock(-1, -1, -1)); - assertFalse(region.containsBlock(-1, -1, 0)); - assertFalse(region.containsBlock(-1, -1, -1)); - assertFalse(region.containsBlock(0, -1, -1)); + BlockRegion region = new BlockRegion(0, 0, 0); + assertTrue(region.contains(0, 0, 0)); + + assertFalse(region.contains(1, 0, 0)); + assertFalse(region.contains(1, 0, 1)); + assertFalse(region.contains(0, 0, 1)); + assertFalse(region.contains(-1, 0, -1)); + assertFalse(region.contains(-1, 0, 0)); + assertFalse(region.contains(-1, 0, -1)); + assertFalse(region.contains(0, 0, -1)); + + assertFalse(region.contains(1, 1, 0)); + assertFalse(region.contains(1, 1, 1)); + assertFalse(region.contains(0, 1, 1)); + assertFalse(region.contains(-1, 1, -1)); + assertFalse(region.contains(-1, 1, 0)); + assertFalse(region.contains(-1, 1, -1)); + assertFalse(region.contains(0, 1, -1)); + + assertFalse(region.contains(1, -1, 0)); + assertFalse(region.contains(1, -1, 1)); + assertFalse(region.contains(0, -1, 1)); + assertFalse(region.contains(-1, -1, -1)); + assertFalse(region.contains(-1, -1, 0)); + assertFalse(region.contains(-1, -1, -1)); + assertFalse(region.contains(0, -1, -1)); } private static Stream testCenterArgs() { return Stream.of( Arguments.of( - new BlockRegion(), + BlockRegion.INVALID, new Vector3f(Float.NaN) ), // creating from min and max Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), + new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), new Vector3f(0f, 0f, 0f) ), Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)), + new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)), new Vector3f(.5f, .5f, .5f) ), Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(1, 1, 1)), + new BlockRegion(new Vector3i(-1, -1, -1), new Vector3i(1, 1, 1)), new Vector3f(0f, 0f, 0f) ), Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(0, 0, 0), new Vector3i(2, 2, 2)), + new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(2, 2, 2)), new Vector3f(1f, 1f, 1f) ), // creating from center and extents Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)), - new Vector3f(0f, 0f, 0f) - ), - Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0.5f, 0.5f, 0.5f), new Vector3f(0.5f, - 0.5f, 0.5f)), - new Vector3f(.5f, .5f, .5f) - ), - Arguments.of( - BlockRegions.createFromCenterAndExtents(new Vector3f(0.49f, 0.49f, 0.49f), new Vector3f(0.5f, - 0.5f, 0.5f)), + new BlockRegion(new Vector3i(0, 0, 0)).expand(new Vector3i(0, 0, 0)), new Vector3f(0f, 0f, 0f) ) - ); } @@ -344,12 +356,12 @@ static Stream containsPointArgs() { @ParameterizedTest @MethodSource("containsPointArgs") public void containsPointPositive(Vector3f point, boolean shouldBeContained) { - BlockRegion region = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); if (shouldBeContained) { - assertTrue(region.containsPoint(point), "point should be within region"); + assertTrue(region.contains(point), "point should be within region"); } else { - assertFalse(region.containsPoint(point), "point should not be within region"); + assertFalse(region.contains(point), "point should not be within region"); } } @@ -357,16 +369,16 @@ public void containsPointPositive(Vector3f point, boolean shouldBeContained) { @Test public void testIntersectionPlane() { - BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion a = new BlockRegion(0, 0, 0, 1, 1, 1); assertTrue(a.intersectsPlane(1, 1, 1, 1)); assertFalse(a.intersectsPlane(1, 1, 1, 2)); } @Test public void testIntersectionBlockRegion() { - BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); - BlockRegion b = BlockRegions.createFromMinAndMax(1, 1, 1, 4, 4, 4); - BlockRegion c = BlockRegions.createFromMinAndMax(3, 3, 3, 4, 4, 4); + BlockRegion a = new BlockRegion(0, 0, 0, 1, 1, 1); + BlockRegion b = new BlockRegion(1, 1, 1, 4, 4, 4); + BlockRegion c = new BlockRegion(3, 3, 3, 4, 4, 4); assertTrue(a.intersectsBlockRegion(b)); assertFalse(a.intersectsBlockRegion(c)); @@ -386,13 +398,13 @@ static Stream testIntersectionAABB() { @ParameterizedTest @MethodSource public void testIntersectionAABB(AABBf aabb, boolean intersects) { - BlockRegion region = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); assertEquals(intersects, region.intersectsAABB(aabb)); } @Test public void testIntersectionSphere() { - BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion a = new BlockRegion(0, 0, 0, 1, 1, 1); Spheref s1 = new Spheref(0, 0, 1, 2); Spheref s2 = new Spheref(3, 3, 3, 1); @@ -404,7 +416,7 @@ public void testIntersectionSphere() { @Test public void testIntersectionRay() { - BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion a = new BlockRegion(0, 0, 0, 1, 1, 1); Rayf r1 = new Rayf(0, 0, 3, 1, 1, -2); Rayf r2 = new Rayf(0, 2, 2, 1, 0, 0); @@ -416,7 +428,7 @@ public void testIntersectionRay() { @Test void testIntersectionLineSegment() { - BlockRegion a = BlockRegions.createFromMinAndMax(0, 0, 0, 1, 1, 1); + BlockRegion a = new BlockRegion(0, 0, 0, 1, 1, 1); //no intersection assertEquals(a.intersectLineSegment(3f, 3f, 3f, 2f, 3f, 3f, new Vector2f()), -1); @@ -442,11 +454,11 @@ void testIntersectionLineSegment() { static Stream getBoundsArgs() { return Stream.of( Arguments.of( - BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2, 3, 4)), + new BlockRegion(new Vector3i(1, 1, 1), new Vector3i(2, 3, 4)), new AABBf(.5f, .5f, .5f, 2.5f, 3.5f, 4.5f) ), Arguments.of( - BlockRegions.createFromMinAndMax(-1, -1, -1, 1, 1, 1), + new BlockRegion(-1, -1, -1, 1, 1, 1), new AABBf(-1.5f, -1.5f, -1.5f, 1.5f, 1.5f, 1.5f) ) ); @@ -461,7 +473,6 @@ void getBounds(BlockRegion region, AABBf bounds) { static Stream copyRegionArgs() { return Stream.of( Arguments.of((Function) region -> new BlockRegion(region)), - Arguments.of((Function) region -> region.copy()), Arguments.of((Function) region -> new BlockRegion(0, 0, 0).set(region)) ); } @@ -469,9 +480,9 @@ static Stream copyRegionArgs() { @ParameterizedTest @MethodSource("copyRegionArgs") void copyRegion(Function copyFn) { - BlockRegion original = BlockRegions.encompassing(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); + BlockRegion original = new BlockRegion(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); - BlockRegion source = BlockRegions.encompassing(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); + BlockRegion source = new BlockRegion(new Vector3i(1, 1, 1), new Vector3i(2, 2, 2)); BlockRegion copy = copyFn.apply(source); assertEquals(original, copy); @@ -481,32 +492,7 @@ void copyRegion(Function copyFn) { assertEquals(new Vector3i(2, 3, 4), copy.getMax(new Vector3i())); } - // -- extend -----------------------------------------------------------------------------------------------------// - - static Stream extendFloatArgs() { - return Stream.of( - Arguments.of(.1f, .1f, .1f, BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(3, 3, 3))), - Arguments.of(-.1f, -.1f, -.1f, BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2 - , 2, 2))), - Arguments.of(1f, 1f, 1f, BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), new Vector3i(4, 4 - , 4))), - Arguments.of(-1f, -1f, -1f, BlockRegions.createFromMinAndMax(new Vector3i(1, 1, 1), new Vector3i(2, 2 - , 2))), - Arguments.of(1.9f, 1.9f, 1.9f, BlockRegions.createFromMinAndMax(new Vector3i(-1, -1, -1), - new Vector3i(4, 4, 4))) - ); - } - - @ParameterizedTest - @MethodSource("extendFloatArgs") - void extendFloat(float x, float y, float z, BlockRegion expected) { - final BlockRegion region = BlockRegions.createFromMinAndMax(new Vector3i(), new Vector3i(3, 3, 3)); - assertEquals(expected, region.copy().extend(x, y, z)); - } - - void extend(int x, int y, int z) { - BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); - } + // -- expand -----------------------------------------------------------------------------------------------------// static Stream extendInvalidArgs() { return Stream.of( @@ -522,8 +508,8 @@ static Stream extendInvalidArgs() { void extendInvalid(Vector3i extents) { BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); - assertThrows(IllegalArgumentException.class, () -> region.extend(extents)); - assertThrows(IllegalArgumentException.class, () -> region.extend(extents.x(), extents.y(), extents.z())); + assertThrows(IllegalArgumentException.class, () -> region.expand(extents)); + assertThrows(IllegalArgumentException.class, () -> region.expand(extents.x(), extents.y(), extents.z())); } // -- union ------------------------------------------------------------------------------------------------------// @@ -545,7 +531,7 @@ static Stream unionArgs() { @MethodSource("unionArgs") public void union(Vector3i vec1, Vector3i vec2) { BlockRegion expected = - BlockRegions.createFromMinAndMax(new Vector3i(-2, 4, -16), new Vector3i(4, 107, 0)); + new BlockRegion(new Vector3i(-2, 4, -16), new Vector3i(4, 107, 0)); assertEquals(expected, new BlockRegion(vec1).union(vec2)); assertEquals(expected, new BlockRegion(vec2).union(vec1)); @@ -569,35 +555,84 @@ static Stream unionWithRegionArgs() { @ParameterizedTest @MethodSource("unionWithRegionArgs") public void unionWithRegion(BlockRegion a, BlockRegion b, BlockRegion expected) { - assertEquals(expected, a.copy().union(b)); - assertEquals(expected, b.copy().union(a)); + assertEquals(expected, new BlockRegion(a).union(b)); + assertEquals(expected, new BlockRegion(b).union(a)); } + // -- translate --------------------------------------------------------------------------------------------------// + @Test - public void unionWithBlockEntity() { - Vector3i pos = new Vector3i(1, 2, 3); - final EntityRef entity = new PojoEntityManager().create(new BlockComponent(new Block(), pos)); + public void translate() { + BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); + Vector3i translation = new Vector3i(1, 2, 3); - BlockRegion region = new BlockRegion().union(entity); - assertTrue(region.containsBlock(pos)); - assertEquals(Collections.singletonList(pos), Lists.newArrayList(BlockRegions.iterable(region))); + assertEquals(new BlockRegion(1, 2, 3, 2, 3, 4), new BlockRegion(region).translate(translation)); + assertEquals(region, + new BlockRegion(region).translate(translation).translate(translation.negate(new Vector3i()))); } + // -- ITERABLE ---------------------------------------------------------------------------------------------------// + @Test - public void unionWithNonBlockEntity() { - final EntityRef entity = new PojoEntityManager().create(); - BlockRegion region = new BlockRegion().union(entity); - assertFalse(region.isValid()); + public void testSingleBlockRegion() { + BlockRegion region = new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)); + + List actual = new ArrayList<>(); + for (Vector3ic vector3ic : region) { + actual.add(new Vector3i(vector3ic)); + } + + Assertions.assertEquals(1, actual.size()); + Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); } - // -- translate --------------------------------------------------------------------------------------------------// + @Test + public void testLineOfBlocksRegion() { + BlockRegion region = new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(0, 1, 0)); + + List actual = new ArrayList<>(); + for (Vector3ic vector3ic : region) { + actual.add(new Vector3i(vector3ic)); + } + + Assertions.assertEquals(2, actual.size()); + Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); + } @Test - public void translate() { - BlockRegion region = new BlockRegion(0, 0, 0, 1, 1, 1); - Vector3i translation = new Vector3i(1, 2, 3); + public void testPlaneOfBlocksRegion() { + BlockRegion region = new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(0, 1, 1)); + + List actual = new ArrayList<>(); + for (Vector3ic vector3ic : region) { + actual.add(new Vector3i(vector3ic)); + } + + Assertions.assertEquals(4, actual.size()); + Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); + } - assertEquals(new BlockRegion(1, 2, 3, 2, 3, 4), region.copy().translate(translation)); - assertEquals(region, region.copy().translate(translation).translate(translation.negate(new Vector3i()))); + @Test + public void testBoxOfBlocksRegion() { + BlockRegion region = new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(1, 1, 1)); + List actual = new ArrayList<>(); + for (Vector3ic vector3ic : region) { + actual.add(new Vector3i(vector3ic)); + } + + Assertions.assertEquals(8, actual.size()); + Assertions.assertEquals(new HashSet<>(expectedPositions(region)), new HashSet<>(actual)); + } + + private List expectedPositions(BlockRegion region) { + List result = new ArrayList<>(region.volume()); + for (int x = region.minX(); x <= region.maxX(); x++) { + for (int y = region.minY(); y <= region.maxY(); y++) { + for (int z = region.minZ(); z <= region.maxZ(); z++) { + result.add(new Vector3i(x, y, z)); + } + } + } + return result; } } diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index 1b3f551af50..66f1bfefac5 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -22,7 +22,6 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; import org.terasology.world.block.OnActivatedBlocks; import org.terasology.world.block.OnAddedBlocks; import org.terasology.world.chunks.Chunk; @@ -92,16 +91,15 @@ public void tearDown() { private Future requestCreatingOrLoadingArea(Vector3i chunkPosition, int radius) { Future chunkFuture = chunkProvider.createOrLoadChunk(chunkPosition); - BlockRegion extentsRegion = BlockRegions.createFromMinAndMax( + BlockRegion extentsRegion = new BlockRegion( chunkPosition.x - radius, chunkPosition.y - radius, chunkPosition.z - radius, chunkPosition.x + radius, chunkPosition.y + radius, chunkPosition.z + radius); - BlockRegions.iterableInPlace(extentsRegion).iterator() - .forEachRemaining(pos -> { - if (!pos.equals(JomlUtil.from(chunkPosition))) { // remove center. we takes future for it already. - chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); - } - }); + extentsRegion.iterator().forEachRemaining(pos -> { + if (!pos.equals(JomlUtil.from(chunkPosition))) { // remove center. we takes future for it already. + chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); + } + }); return chunkFuture; } diff --git a/engine/src/main/java/org/terasology/math/ChunkMath.java b/engine/src/main/java/org/terasology/math/ChunkMath.java index 2d7026f8052..8f8dc785190 100644 --- a/engine/src/main/java/org/terasology/math/ChunkMath.java +++ b/engine/src/main/java/org/terasology/math/ChunkMath.java @@ -22,7 +22,7 @@ import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.chunks.ChunkConstants; import java.math.RoundingMode; @@ -270,8 +270,8 @@ public static org.joml.Vector3i calcChunkPos(int x, int y, int z, int chunkX, in */ public static BlockRegion calcChunkRegion(BlockRegion region, int chunkX, int chunkY, int chunkZ, BlockRegion dest) { return dest. - setMin(calcChunkPos(region.getMinX(), chunkX), calcChunkPos(region.getMinY(), chunkY), calcChunkPos(region.getMinZ(), chunkZ)). - setMax(calcChunkPos(region.getMaxX(), chunkX), calcChunkPos(region.getMaxY(), chunkY), calcChunkPos(region.getMaxZ(), chunkZ)); + setMin(calcChunkPos(region.minX(), chunkX), calcChunkPos(region.minY(), chunkY), calcChunkPos(region.minZ(), chunkZ)). + setMax(calcChunkPos(region.maxX(), chunkX), calcChunkPos(region.maxY(), chunkY), calcChunkPos(region.maxZ(), chunkZ)); } /** @@ -492,7 +492,7 @@ public static BlockRegion getChunkRegionAroundWorldPos(Vector3ic pos, int extent org.joml.Vector3i temp = new org.joml.Vector3i(); org.joml.Vector3i minChunk = calcChunkPos(temp.set(pos).add(-extent, -extent, -extent), new org.joml.Vector3i()); org.joml.Vector3i maxChunk = calcChunkPos(temp.set(pos).add(extent, extent, extent), new org.joml.Vector3i()); - return BlockRegions.createFromMinAndMax(minChunk, maxChunk); + return new BlockRegion(minChunk, maxChunk); } @@ -532,7 +532,7 @@ public static Side getSecondaryPlacementDirection(Vector3fc direction, Vector3fc * @param side * @return * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getEdgeRegion(BlockRegion, Side, BlockRegion)}. + * method will be replaced with JOML implementation {@link #getEdgeRegion(BlockRegionc, Side, BlockRegion)}. */ @Deprecated public static Region3i getEdgeRegion(Region3i region, Side side) { @@ -571,73 +571,65 @@ public static Region3i getEdgeRegion(Region3i region, Side side) { * @param dest will hold the result * @return dest */ - public static BlockRegion getEdgeRegion(BlockRegion region, Side side, BlockRegion dest) { + public static BlockRegion getEdgeRegion(BlockRegionc region, Side side, BlockRegion dest) { switch (side) { case TOP: - return dest.setMin( - region.getMinX(), - region.getMaxY(), - region.getMinZ() - ).setMax( - region.getMaxX(), - region.getMaxY(), - region.getMaxZ()); + return dest.set( + region.minX(), + region.maxY(), + region.minZ(), + region.maxX(), + region.maxY(), + region.maxZ()); case BOTTOM: - return dest.setMin( - region.getMinX(), - region.getMinY(), - region.getMinZ() - ).setMax( - region.getMaxX(), - region.getMinY(), - region.getMaxZ()); + return dest.set( + region.minX(), + region.minY(), + region.minZ(), + region.maxX(), + region.minY(), + region.maxZ()); case LEFT: - return dest.setMin( - region.getMinX(), - region.getMinY(), - region.getMinZ() - ).setMax( - region.getMinX(), - region.getMaxY(), - region.getMaxZ()); + return dest.set( + region.minX(), + region.minY(), + region.minZ(), + region.minX(), + region.maxY(), + region.maxZ()); case RIGHT: - return dest.setMin( - region.getMaxX(), - region.getMinY(), - region.getMinZ() - ).setMax( - region.getMaxX(), - region.getMaxY(), - region.getMaxZ()); + return dest.set( + region.maxX(), + region.minY(), + region.minZ(), + region.maxX(), + region.maxY(), + region.maxZ()); case FRONT: - return dest.setMin( - region.getMinX(), - region.getMinY(), - region.getMinZ() - ).setMax( - region.getMaxX(), - region.getMaxY(), - region.getMinZ()); + return dest.set( + region.minX(), + region.minY(), + region.minZ(), + region.maxX(), + region.maxY(), + region.minZ()); case BACK: - return dest.setMin( - region.getMinX(), - region.getMinY(), - region.getMaxZ() - ).setMax( - region.getMaxX(), - region.getMaxY(), - region.getMaxZ()); + return dest.set( + region.minX(), + region.minY(), + region.maxZ(), + region.maxX(), + region.maxY(), + region.maxZ()); default: - return dest.setMin( - region.getMinX(), - region.getMinY(), - region.getMinZ() - ).setMax( - region.getMaxX(), - region.getMaxY(), - region.getMaxZ() + return dest.set( + region.minX(), + region.minY(), + region.minZ(), + region.maxX(), + region.maxY(), + region.maxZ() ); - } } diff --git a/engine/src/main/java/org/terasology/math/JomlUtil.java b/engine/src/main/java/org/terasology/math/JomlUtil.java index 306ee81661b..91004e5c964 100644 --- a/engine/src/main/java/org/terasology/math/JomlUtil.java +++ b/engine/src/main/java/org/terasology/math/JomlUtil.java @@ -44,7 +44,6 @@ import org.terasology.math.geom.Vector3f; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; import java.util.Map; import java.util.stream.Collectors; @@ -195,7 +194,8 @@ public static BlockRegion from(Region3i aabb) { if (aabb == null) { return null; } - return BlockRegions.createFromMinAndMax(aabb.minX(), aabb.minY(), aabb.minZ(), aabb.maxX(), aabb.maxY(), aabb.maxZ()); + //TODO: is this conversion correct, or is it off by one (max incl. vs max excl.) + return new BlockRegion(aabb.minX(), aabb.minY(), aabb.minZ(), aabb.maxX(), aabb.maxY(), aabb.maxZ()); } diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java index 2080b2a5c2b..97c5edb8482 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandler.java @@ -11,7 +11,6 @@ import org.terasology.persistence.typeHandling.PersistedDataSerializer; import org.terasology.persistence.typeHandling.TypeHandler; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; import java.util.Map; import java.util.Optional; @@ -43,16 +42,17 @@ public Optional deserialize(PersistedData data) { PersistedDataArray sizedataArray = map.get(SIZE_FIELD).getAsArray(); TIntList sizeArr = sizedataArray.getAsIntegerArray(); return Optional.of( - BlockRegions.createFromMinAndMax( + new BlockRegion( minArr.get(0), minArr.get(1), minArr.get(2), - minArr.get(0) + sizeArr.get(0) - 1, minArr.get(1) + sizeArr.get(1) - 1, + minArr.get(0) + sizeArr.get(0) - 1, + minArr.get(1) + sizeArr.get(1) - 1, minArr.get(2) + sizeArr.get(2) - 1)); } PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); TIntList maxArr = maxDataArr.getAsIntegerArray(); return Optional.of( - BlockRegions.createFromMinAndMax( + new BlockRegion( minArr.get(0), minArr.get(1), minArr.get(2), maxArr.get(0), maxArr.get(1), maxArr.get(2))); } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegion.java b/engine/src/main/java/org/terasology/world/block/BlockRegion.java index e3c243d45a3..d03c50215a5 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegion.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegion.java @@ -3,28 +3,21 @@ package org.terasology.world.block; import com.google.common.base.Preconditions; -import org.joml.AABBf; -import org.joml.Intersectionf; -import org.joml.LineSegmentf; import org.joml.Math; import org.joml.Matrix4fc; -import org.joml.Planef; -import org.joml.Rayf; import org.joml.RoundingMode; -import org.joml.Spheref; -import org.joml.Vector2f; -import org.joml.Vector3f; -import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.entitySystem.entity.EntityRef; +import java.util.Iterator; import java.util.Optional; /** - * A bounded, axis-aligned volume in space denoting a collection of blocks contained within. + * A mutable, bounded, axis-aligned volume in space denoting a collection of blocks contained within. */ -public class BlockRegion { +public class BlockRegion implements BlockRegionc { + + public static final BlockRegionc INVALID = new BlockRegion(); /** * The x coordinate of the minimum corner. @@ -54,37 +47,54 @@ public class BlockRegion { // -- CONSTRUCTORS -----------------------------------------------------------------------------------------------// /** - * Creates an empty block region with invalid minimum/maximum corners. + * INTERNAL: Creates an empty block region with invalid minimum/maximum corners. *

* {@link #isValid()} will return {@code false} for an empty block region created via this constructor. */ - @Deprecated BlockRegion() { } - BlockRegion(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - Preconditions.checkArgument(minX <= maxX); - Preconditions.checkArgument(minY <= maxY); - Preconditions.checkArgument(minZ <= maxZ); - - this.minX = minX; - this.minY = minY; - this.minZ = minZ; - - this.maxX = maxX; - this.maxY = maxY; - this.maxZ = maxZ; + /** + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. + *

+ * Note that each component of the minimum corner MUST be smaller or equal to the respective component of the + * maximum corner. If a dimension of {@code min} is greater than the respective dimension of {@code max} an {@link + * IllegalArgumentException} will be thrown. + *

+ * Consider using {@link #union(Vector3ic)} as an alternative. + * + * @throws IllegalArgumentException if any min component is greater than the corresponding max component + */ + public BlockRegion(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + this.set(minX, minY, minZ, maxX, maxY, maxZ); } - BlockRegion(Vector3ic min, Vector3ic max) { - this(min.x(), min.y(), min.z(), max.x(), max.y(), max.z()); + /** + * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. + *

+ * Note that each component of the minimum corner MUST be smaller or equal to the respective component of the + * maximum corner. If a dimension of {@code min} is greater than the respective dimension of {@code max} an {@link + * IllegalArgumentException} will be thrown. + *

+ * Consider using {@link #union(Vector3ic)} as an alternative. + * + * @throws IllegalArgumentException if any min component is greater than the corresponding max component + */ + public BlockRegion(Vector3ic min, Vector3ic max) { + this.set(min.x(), min.y(), min.z(), max.x(), max.y(), max.z()); } - BlockRegion(int x, int y, int z) { - this(x, y, z, x, y, z); + /** + * Creates a new region containing the single block given by the coordinates. + */ + public BlockRegion(int x, int y, int z) { + this.set(x, y, z, x, y, z); } - BlockRegion(Vector3ic block) { + /** + * Creates a new region containing the single block given by the coordinates. + */ + public BlockRegion(Vector3ic block) { this(block.x(), block.y(), block.z()); } @@ -93,550 +103,355 @@ public class BlockRegion { * * @param source the block region to copy. */ - public BlockRegion(BlockRegion source) { + public BlockRegion(BlockRegionc source) { this.set(source); } + // -- ITERABLE ---------------------------------------------------------------------------------------------------// + + @Override + public Iterator iterator() { + return new Iterator() { + private Vector3i current = null; + private final Vector3i next = getMin(new Vector3i()); + + public boolean findNext() { + if (current.equals(next)) { + next.z++; + if (next.z > maxZ) { + next.z = minZ; + next.y++; + if (next.y > maxY) { + next.y = minY; + next.x++; + } + } + return contains(next); + } + return true; + } + + @Override + public boolean hasNext() { + if (!isValid()) { + return false; + } + if (current == null) { + return true; + } + + if (current.equals(next)) { + return findNext(); + } + return contains(next); + } + + @Override + public Vector3ic next() { + if (current == null) { + current = new Vector3i(next); + return next; + } + + if (current.equals(next)) { + if (findNext()) { + return next; + } + return null; + } + current.set(next); + return next; + } + }; + } + // -- GETTERS & SETTERS ------------------------------------------------------------------------------------------// /** - * set source to current region + * Reset both the minimum and maximum corner of this region. * - * @param source the source region - * @return this + * @return this region (after modification) + * @throws IllegalArgumentException if the given coordinates for min and max are {@link #isValid() + * invalid}. */ - public BlockRegion set(BlockRegion source) { - this.minX = source.minX; - this.minY = source.minY; - this.minZ = source.minZ; - - this.maxX = source.maxX; - this.maxY = source.maxY; - this.maxZ = source.maxZ; - return this; - } + public BlockRegion set(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + Preconditions.checkArgument(minX <= maxX || (minX == INVALID.minX() && maxX == INVALID.maxX())); + Preconditions.checkArgument(minY <= maxY || (minY == INVALID.minY() && maxY == INVALID.maxY())); + Preconditions.checkArgument(minZ <= maxZ || (minZ == INVALID.minZ() && maxZ == INVALID.maxZ())); + this.minX = minX; + this.minY = minY; + this.minZ = minZ; - public BlockRegion copy() { - return new BlockRegion(this); + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + return this; } - // -- min --------------------------------------------------------------------------------------------------------// - /** - * The x-coordinate of the minimum corner + * Reset both the minimum and maximum corner of this region. + * + * @return this region (after modification) + * @throws IllegalArgumentException if the given coordinates for min and max are {@link #isValid() + * invalid}. */ - public int minX() { - return this.minX; + public BlockRegion set(Vector3ic min, Vector3ic max) { + return this.set(min.x(), min.y(), min.z(), max.x(), max.y(), max.z()); } /** - * the minimum coordinate of the first block x + * Reset this region to have the same minimum and maximum corner as the {@code source} region. * - * @return the minimum coordinate x - * @deprecated use {@link #minX()} + * @return this region (after modification) + * @throws IllegalArgumentException if the given coordinates for min and max are {@link #isValid() + * invalid}. */ - @Deprecated - public int getMinX() { - return this.minX; + public BlockRegion set(BlockRegionc source) { + return this.set(source.minX(), source.minY(), source.minZ(), source.maxX(), source.maxY(), source.maxZ()); } - /** - * set the minimum coordinate of the first block x - * - * @return the minX - */ - public BlockRegion minX(int x) { - Preconditions.checkArgument(x <= this.maxX || this.maxX == Integer.MIN_VALUE); - this.minX = x; - return this; + // -- min --------------------------------------------------------------------------------------------------------// + + @Override + public int minX() { + return this.minX; } - /** - * The y-coordinate of the minimum corner - */ + @Override public int minY() { return this.minY; } - /** - * the minimum coordinate of the first block y - * - * @return the minimum coordinate y - * @deprecated use {@link #minY()} - */ - @Deprecated - public int getMinY() { - return this.minY; + @Override + public int minZ() { + return this.minZ; } - /** - * set the minimum coordinate of the first block y - * - * @return the minY - */ - public BlockRegion minY(int y) { - Preconditions.checkArgument(y <= this.maxY || this.maxY == Integer.MIN_VALUE); - this.minY = y; - return this; + @Override + public BlockRegion minX(int x, BlockRegion dest) { + return dest.set(x, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); } - /** - * The z-coordinate of the minimum corner - */ - public int minZ() { - return this.minZ; + public BlockRegion minX(int x) { + return this.minX(x, this); } - /** - * the minimum coordinate of the first block z - * - * @return the minimum coordinate z - * @deprecated use {@link #minZ()} - */ - @Deprecated - public int getMinZ() { - return this.minZ; + @Override + public BlockRegion minY(int y, BlockRegion dest) { + return dest.set(this.minX, y, this.minZ, this.maxX, this.maxY, this.maxZ); } - /** - * set the minimum coordinate of the first block z - * - * @return the minZ - */ - public BlockRegion minZ(int z) { - Preconditions.checkArgument(z <= this.maxZ || this.maxZ == Integer.MIN_VALUE); - this.minZ = z; - return this; + public BlockRegion minY(int y) { + return this.minY(y, this); } - /** - * Get the block coordinate minimum corner. - * - * @param dest will hold the result - */ - public Vector3i getMin(Vector3i dest) { - return dest.set(minX, minY, minZ); + @Override + public BlockRegion minZ(int z, BlockRegion dest) { + return dest.set(this.minX, this.minY, z, this.maxX, this.maxY, this.maxZ); } - /** - * Sets the minimum coordinate of the first block for this {@link BlockRegion} - * - * @param min the first coordinate of the first block - * @return this - */ - public BlockRegion setMin(Vector3ic min) { - return this.setMin(min.x(), min.y(), min.z()); + public BlockRegion minZ(int z) { + return this.minZ(z, this); } - /** - * sets the minimum block for this {@link BlockRegion} - * - * @param minX the x coordinate of the first block - * @param minY the y coordinate of the first block - * @param minZ the z coordinate of the first block - * @return this - */ - public BlockRegion setMin(int minX, int minY, int minZ) { - Preconditions.checkArgument(minX <= this.maxX || this.maxX == Integer.MIN_VALUE); - Preconditions.checkArgument(minY <= this.maxY || this.maxX == Integer.MIN_VALUE); - Preconditions.checkArgument(minZ <= this.maxZ || this.maxX == Integer.MIN_VALUE); - this.minX = minX; - this.minY = minY; - this.minZ = minZ; - return this; + @Override + public BlockRegion setMin(int x, int y, int z, BlockRegion dest) { + return dest.set(x, y, z, this.maxX, this.maxY, this.maxZ); } - // -- max --------------------------------------------------------------------------------------------------------// - - /** - * The x-coordinate of the maximum corner - */ - public int maxX() { - return this.maxX; + public BlockRegion setMin(int x, int y, int z) { + return this.setMin(x, y, z, this); } - /** - * the maximum coordinate of the second block x - * - * @return the minimum coordinate x - * @deprecated use {@link #maxX()} - */ - @Deprecated - public int getMaxX() { - return this.maxX; + public BlockRegion setMin(Vector3ic min) { + return this.setMin(min, this); } - /** - * set the maximum coordinate of the second block x - * - * @return the minX - */ - public BlockRegion maxX(int x) { - Preconditions.checkArgument(x >= this.minX || this.minX == Integer.MAX_VALUE); - this.maxX = x; - return this; + public BlockRegion addToMin(int dx, int dy, int dz) { + return this.addToMin(dx, dy, dz, this); } - /** - * The y-coordinate of the maximum corner - */ - public int maxY() { - return this.maxY; + public BlockRegion addToMin(Vector3ic dmin) { + return this.addToMin(dmin, this); } - /** - * the maximum coordinate of the second block y - * - * @return the minimum coordinate y - * @deprecated use {@link #maxY()} - */ - @Deprecated - public int getMaxY() { - return this.maxY; + + // -- max --------------------------------------------------------------------------------------------------------// + + @Override + public int maxX() { + return this.maxX; } - /** - * set the maximum coordinate of the second block y - * - * @return the minY - */ - public BlockRegion maxY(int y) { - Preconditions.checkArgument(y >= this.minY || this.minY == Integer.MAX_VALUE); - this.maxY = y; - return this; + @Override + public int maxY() { + return this.maxY; } - /** - * The z-coordinate of the maximum corner - */ + @Override public int maxZ() { return this.maxZ; } - /** - * the maximum coordinate of the second block z - * - * @return the minimum coordinate z - * @deprecated use {@link #maxZ()} - */ - @Deprecated - public int getMaxZ() { - return this.maxZ; + @Override + public BlockRegion maxX(int x, BlockRegion dest) { + return dest.set(this.minX, this.minY, this.minZ, x, this.maxY, this.maxZ); } - /** - * set the maximum coordinate of the second block z - * - * @return the minZ - */ - public BlockRegion maxZ(int z) { - Preconditions.checkArgument(z >= this.minZ || this.minZ == Integer.MAX_VALUE); - this.maxZ = z; - return this; + public BlockRegion maxX(int x) { + return this.maxX(x, this); } - /** - * Get the block coordinate of the maximum corner. - * - * @param dest will hold the result - */ - public Vector3i getMax(Vector3i dest) { - return dest.set(maxX, maxY, maxZ); + @Override + public BlockRegion maxY(int y, BlockRegion dest) { + return dest.set(this.minX, this.minY, this.minZ, this.maxX, y, this.maxZ); } - /** - * Sets the maximum coordinate of the second block for this {@link BlockRegion} - * - * @param max the second coordinate of the second block - * @return this - */ - public BlockRegion setMax(Vector3ic max) { - return this.setMax(max.x(), max.y(), max.z()); + public BlockRegion maxY(int y) { + return this.maxY(y, this); } - /** - * sets the maximum block for this {@link BlockRegion} - * - * @param maxX the x coordinate of the first block - * @param maxY the y coordinate of the first block - * @param maxZ the z coordinate of the first block - * @return this - */ - public BlockRegion setMax(int maxX, int maxY, int maxZ) { - Preconditions.checkArgument(maxX >= this.minX || this.minX == Integer.MAX_VALUE); - Preconditions.checkArgument(maxY >= this.minY || this.minY == Integer.MAX_VALUE); - Preconditions.checkArgument(maxZ >= this.minZ || this.minZ == Integer.MAX_VALUE); - this.maxX = maxX; - this.maxY = maxY; - this.maxZ = maxZ; - return this; + @Override + public BlockRegion maxZ(int z, BlockRegion dest) { + return dest.set(this.minX, this.minY, this.minZ, this.maxX, this.maxY, z); } - // -- size -------------------------------------------------------------------------------------------------------// - - /** - * Set the size of the block region from minimum the minimum corner. - * - * @param x the x coordinate to set the size; must be > 0 - * @param y the y coordinate to set the size; must be > 0 - * @param z the z coordinate to set the size; must be > 0 - * @return this after modification - */ - public BlockRegion setSize(int x, int y, int z) { - Preconditions.checkArgument(x > 0); - Preconditions.checkArgument(y > 0); - Preconditions.checkArgument(z > 0); - this.maxX = this.minX + x - 1; - this.maxY = this.minY + y - 1; - this.maxZ = this.minZ + z - 1; - return this; + public BlockRegion maxZ(int z) { + return this.maxZ(z, this); } - /** - * Set the size of the block region from minimum the minimum corner. - * - * @param size the size to set; all dimensions must be > 0 - * @return this after modification - */ - public BlockRegion setSize(Vector3ic size) { - return setSize(size.x(), size.y(), size.z()); + @Override + public BlockRegion setMax(int x, int y, int z, BlockRegion dest) { + return dest.set(this.minX, this.minY, this.minZ, x, y, z); } - /** - * the number of blocks for the +x, +y, +z from the minimum to the maximum - * - * @param dest will hold the result - * @return dest - */ - public Vector3i getSize(Vector3i dest) { - return dest.set(sizeX(), sizeY(), sizeZ()); + public BlockRegion setMax(int x, int y, int z) { + return this.setMax(x, y, z, this); } - /** - * The number of blocks on the X axis - * - * @return number of blocks in the X axis - */ - public int sizeX() { - return this.maxX - this.minX + 1; + public BlockRegion setMax(Vector3ic max) { + return this.setMax(max, this); } - /** - * The number of blocks on the Y axis - * - * @return number of blocks in the Y axis - */ - public int sizeY() { - return this.maxY - this.minY + 1; + public BlockRegion addToMax(int dx, int dy, int dz) { + return this.addToMax(dx, dy, dz, this); } - /** - * The number of blocks on the Z axis - * - * @return number of blocks in the Z axis - */ - public int sizeZ() { - return this.maxZ - this.minZ + 1; + public BlockRegion addToMax(Vector3ic dmax) { + return this.addToMax(dmax, this); } - // -- world ------------------------------------------------------------------------------------------------------// - - //TODO: 1.9.26 has a constant interface for aabbf - public AABBf getBounds(AABBf dest) { - dest.minX = minX - .5f; - dest.minY = minY - .5f; - dest.minZ = minZ - .5f; + // -- size -------------------------------------------------------------------------------------------------------// - dest.maxX = maxX + .5f; - dest.maxY = maxY + .5f; - dest.maxZ = maxZ + .5f; + @Override + public BlockRegion setSize(int x, int y, int z, BlockRegion dest) { + return dest.set(this.minX, this.minY, this.minZ, this.minX + x - 1, this.minY + y - 1, this.minZ + z - 1); + } - return dest; + public BlockRegion setSize(int x, int y, int z) { + return this.setSize(x, y, z, this); } - /** - * The center of the region if the region is valid, {@link Float#NaN} in all dimensions otherwise. - * - * @param dest will hold the result - * @return dest - */ - public Vector3f center(Vector3f dest) { - if (!this.isValid()) { - return dest.set(Float.NaN); - } - return dest.set( - (this.minX - .5f) + ((this.maxX - this.minX + 1.0f) / 2.0f), - (this.minY - .5f) + ((this.maxY - this.minY + 1.0f) / 2.0f), - (this.minZ - .5f) + ((this.maxZ - this.minZ + 1.0f) / 2.0f) - ); + public BlockRegion setSize(Vector3ic size) { + return setSize(size.x(), size.y(), size.z()); } // -- IN-PLACE MUTATION ------------------------------------------------------------------------------------------// + @Override + public BlockRegion union(int x, int y, int z, BlockRegion dest) { + dest.minX = Math.min(this.minX, x); + dest.minY = Math.min(this.minY, y); + dest.minZ = Math.min(this.minZ, z); + + dest.maxX = Math.max(this.maxX, x); + dest.maxY = Math.max(this.maxY, y); + dest.maxZ = Math.max(this.maxZ, z); + return dest; + } - /** - * Compute the union of this and the given block (x, y, z). - * - * @param x the x coordinate of the block - * @param y the y coordinate of the block - * @param z the z coordinate of the block - */ public BlockRegion union(int x, int y, int z) { - this.minX = Math.min(this.minX, x); - this.minY = Math.min(this.minY, y); - this.minZ = Math.min(this.minZ, z); - - this.maxX = Math.max(this.maxX, x); - this.maxY = Math.max(this.maxY, y); - this.maxZ = Math.max(this.maxZ, z); - return this; + return this.union(x, y, z, this); } - /** - * Set this to the union of this and the given block pos. - * - * @param pos the position of the block - * @return this - */ public BlockRegion union(Vector3ic pos) { - return union(pos.x(), pos.y(), pos.z()); - } - - /** - * Set this to the union of this and other. - * - * @param other {@link BlockRegion} - * @return this - */ - public BlockRegion union(BlockRegion other) { - return this.union(other.minX, other.minY, other.minZ).union(other.maxX, other.maxY, other.maxZ); + return union(pos.x(), pos.y(), pos.z(), this); } - /** - * Set this to the union of this and the given {@link EntityRef} associated with a block - * p. - * - * @param blockRef entityRef that describes a block - */ - public BlockRegion union(EntityRef blockRef) { - BlockComponent component = blockRef.getComponent(BlockComponent.class); - if (component != null) { - return this.union(component.position.x(), component.position.y(), component.position.z()); - } - return this; + public BlockRegion union(BlockRegionc other) { + return this.union(other, this); } // ---------------------------------------------------------------------------------------------------------------// - /** - * calculate the BlockRegion that is intersected between another region - * - * @param other the other BlockRegion - */ - public Optional intersect(BlockRegion other) { - this.minX = Math.max(minX, other.minX); - this.minY = Math.max(minY, other.minY); - this.minZ = Math.max(minZ, other.minZ); + @Override + public Optional intersect(BlockRegionc other, BlockRegion dest) { + dest.minX = Math.max(minX, other.minX()); + dest.minY = Math.max(minY, other.minY()); + dest.minZ = Math.max(minZ, other.minZ()); - this.maxX = Math.min(maxX, other.maxX); - this.maxY = Math.min(maxY, other.maxY); - this.maxZ = Math.min(maxZ, other.maxZ); + dest.maxX = Math.min(maxX, other.maxX()); + dest.maxY = Math.min(maxY, other.maxY()); + dest.maxZ = Math.min(maxZ, other.maxZ()); - if (this.isValid()) { - return Optional.of(this); + if (dest.isValid()) { + return Optional.of(dest); } else { return Optional.empty(); } } + public Optional intersect(BlockRegionc other) { + return this.intersect(other, this); + } + // ---------------------------------------------------------------------------------------------------------------// - /** - * Translate this by the given vector xyz. - * - * @param x the x coordinate to translate by - * @param y the y coordinate to translate by - * @param z the z coordinate to translate by - */ + @Override + public BlockRegion translate(int x, int y, int z, BlockRegion dest) { + dest.minX = this.minX + x; + dest.minY = this.minY + y; + dest.minZ = this.minZ + z; + dest.maxX = this.maxX + x; + dest.maxY = this.maxY + y; + dest.maxZ = this.maxZ + z; + return dest; + } + public BlockRegion translate(int x, int y, int z) { - this.minX = this.minX + x; - this.minY = this.minY + y; - this.minZ = this.minZ + z; - this.maxX = this.maxX + x; - this.maxY = this.maxY + y; - this.maxZ = this.maxZ + z; - return this; + return this.translate(x, y, z, this); } - /** - * Translate this by the given vector vec. - * - * @param vec the vector to translate by - * @return this - */ public BlockRegion translate(Vector3ic vec) { return translate(vec.x(), vec.y(), vec.z()); } - // ---------------------------------------------------------------------------------------------------------------// + public BlockRegion setPosition(int x, int y, int z) { + return this.setPosition(x, y, z, this); + } - /** - * Adds extend for each face of a BlockRegion - * - * @param extentX the x coordinate to grow the extents - * @param extentY the y coordinate to grow the extents - * @param extentZ the z coordinate to grow the extents - */ - public BlockRegion extend(int extentX, int extentY, int extentZ) { - Preconditions.checkArgument(sizeX() + 2 * extentX > 0); - Preconditions.checkArgument(sizeY() + 2 * extentY > 0); - Preconditions.checkArgument(sizeZ() + 2 * extentZ > 0); - this.minX = this.minX - extentX; - this.minY = this.minY - extentY; - this.minZ = this.minZ - extentZ; - - this.maxX = this.maxX + extentX; - this.maxY = this.maxY + extentY; - this.maxZ = this.maxZ + extentZ; + public BlockRegion setPosition(Vector3ic pos) { + return this.setPosition(pos.x(), pos.y(), pos.z(), this); + } - return this; + @Override + public BlockRegion expand(int dx, int dy, int dz, BlockRegion dest) { + return dest.set(this.minX - dx, this.minY - dy, this.minZ - dz, + this.maxX + dx, this.maxY + dy, this.maxZ + dz); } - /** - * Adds extend for each face of a BlockRegion. - * - * @param extents the coordinates to grow the extents - * @return this - */ - public BlockRegion extend(Vector3ic extents) { - return extend(extents.x(), extents.y(), extents.z()); + public BlockRegion expand(int dx, int dy, int dz) { + return this.expand(dx, dy, dz, this); } - /** - * Adds extend for each face of a BlockRegion. - * - * @param extentX the x coordinate to grow the extents - * @param extentY the y coordinate to grow the extents - * @param extentZ the z coordinate to grow the extents - * @return dest - */ - public BlockRegion extend(float extentX, float extentY, float extentZ) { - return extend( - Math.roundUsing(extentX, RoundingMode.FLOOR), - Math.roundUsing(extentY, RoundingMode.FLOOR), - Math.roundUsing(extentZ, RoundingMode.FLOOR)); + public BlockRegion expand(Vector3ic extents) { + return expand(extents.x(), extents.y(), extents.z()); } - // ---------------------------------------------------------------------------------------------------------------// + // -- transform --------------------------------------------------------------------------------------------------// - /** - * Apply the given {@link Matrix4fc#isAffine() affine} transformation to this {@link BlockRegion}. - *

- * The matrix in m must be {@link Matrix4fc#isAffine() affine}. - * - * @param m the affine transformation matrix - * @return this - */ + @Override public BlockRegion transform(Matrix4fc m, BlockRegion dest) { + Preconditions.checkArgument(m.isAffine()); float dx = maxX - minX; float dy = maxY - minY; float dz = maxZ - minZ; @@ -670,324 +485,17 @@ public BlockRegion transform(Matrix4fc m, BlockRegion dest) { return dest; } - /** - * Apply the given {@link Matrix4fc#isAffine() affine} transformation to this {@link BlockRegion}. - *

- * The matrix in m must be {@link Matrix4fc#isAffine() affine}. - * - * @param m the affine transformation matrix - * @return this - */ public BlockRegion transform(Matrix4fc m) { return transform(m, this); } - // -- CHECKS -----------------------------------------------------------------------------------------------------// - - /** - * Check whether this BlockRegion represents a valid BlockRegion. - * - * @return true iff this BlockRegion is valid; false otherwise - */ - public boolean isValid() { - return minX <= maxX && minY <= maxY && minZ <= maxZ; - } - - - // -- contains ---------------------------------------------------------------------------------------------------// - - /** - * Test whether the block (x, y, z) lies inside this BlockRegion. - * - * @param pos the coordinates of the block - * @return true iff the given point lies inside this AABB; false otherwise - */ - public boolean containsBlock(Vector3ic pos) { - return containsBlock(pos.x(), pos.y(), pos.z()); - } - - /** - * Test whether the block (x, y, z) lies inside this BlockRegion. - * - * @param x the x coordinate of the point - * @param y the y coordinate of the point - * @param z the z coordinate of the point - * @return true iff the given point lies inside this AABB; false otherwise - */ - public boolean containsBlock(int x, int y, int z) { - return x >= minX && y >= minY && z >= minZ && x <= maxX && y <= maxY && z <= maxZ; - } - - /** - * Test whether the point (x, y, z) lies inside this BlockRegion. - * - * @param x the x coordinate of the point - * @param y the y coordinate of the point - * @param z the z coordinate of the point - * @return true iff the given point lies inside this BlockRegion; false otherwise - */ - public boolean containsPoint(float x, float y, float z) { - return x >= (this.minX - .5f) - && y >= (this.minY - .5f) - && z >= (this.minZ - .5f) - && x <= (this.maxX + .5f) - && y <= (this.maxY + .5f) - && z <= (this.maxZ + .5f); - } - - /** - * Test whether the given point lies inside this AABB. - * - * @param point the coordinates of the point - * @return true iff the given point lies inside this AABB; false otherwise - */ - public boolean containsPoint(Vector3fc point) { - return this.containsPoint(point.x(), point.y(), point.z()); - } - - // -- intersects -------------------------------------------------------------------------------------------------// - - /** - * Test whether the plane given via its plane equation a*x + b*y + c*z + d = 0 intersects this AABB. - *

- * Reference: - * http://www.lighthouse3d.com - * ("Geometric Approach - Testing Boxes II") - * - * @param a the x factor in the plane equation - * @param b the y factor in the plane equation - * @param c the z factor in the plane equation - * @param d the constant in the plane equation - * @return true iff the plane intersects this AABB; false otherwise - */ - public boolean intersectsPlane(float a, float b, float c, float d) { - return Intersectionf.testAabPlane( - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, a, b, c, d); - } - - /** - * Test whether the given plane intersects this AABB. - *

- * Reference: - * http://www.lighthouse3d.com - * ("Geometric Approach - Testing Boxes II") - * - * @param plane the plane - * @return true iff the plane intersects this AABB; false otherwise - */ - public boolean intersectsPlane(Planef plane) { - return Intersectionf.testAabPlane( - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, - plane.a, - plane.b, - plane.c, - plane.d - ); - } - - /** - * Test whether this and other intersect. - * - * @param other the other BlockRegion - * @return true iff both AABBs intersect; false otherwise - */ - public boolean intersectsBlockRegion(BlockRegion other) { - return this.maxX >= other.minX && this.maxY >= other.minY && this.maxZ >= other.minZ && - this.minX <= other.maxX && this.minY <= other.maxY && this.minZ <= other.maxZ; - } - - /** - * Test whether this and other intersect. - * - * @param other the other AABB - * @return true iff both AABBs intersect; false otherwise - */ - public boolean intersectsAABB(AABBf other) { - return Intersectionf.testAabAab( - this.minX - .5f, this.minY - .5f, this.minZ - .5f, - this.maxX + .5f, this.maxY + .5f, this.maxZ + .5f, - other.minX, other.minY, other.minZ, - other.maxX, other.maxY, other.maxZ - ); - } - - /** - * Test whether this AABB intersects the given sphere with equation - * (x - centerX)^2 + (y - centerY)^2 + (z - centerZ)^2 - radiusSquared = 0. - *

- * Reference: - * http://stackoverflow.com - * - * @param centerX the x coordinate of the center of the sphere - * @param centerY the y coordinate of the center of the sphere - * @param centerZ the z coordinate of the center of the sphere - * @param radiusSquared the square radius of the sphere - * @return true iff this AABB and the sphere intersect; false otherwise - */ - public boolean intersectsSphere(float centerX, float centerY, float centerZ, float radiusSquared) { - return Intersectionf.testAabSphere( - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, - centerX, - centerY, - centerZ, - radiusSquared - ); - } - - /** - * Test whether this AABB intersects the given sphere. - *

- * Reference: - * http://stackoverflow.com - * - * @param sphere the sphere - * @return true iff this AABB and the sphere intersect; false otherwise - */ - public boolean intersectsSphere(Spheref sphere) { - return Intersectionf.testAabSphere( - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, - sphere.x, - sphere.y, - sphere.z, - sphere.r * sphere.r - ); - } - - /** - * Test whether the given ray with the origin (originX, originY, originZ) and direction (dirX, - * dirY, dirZ) intersects this AABB. - *

- * This method returns true for a ray whose origin lies inside this AABB. - *

- * Reference: An Efficient and Robust Ray–Box Intersection - * - * @param originX the x coordinate of the ray's origin - * @param originY the y coordinate of the ray's origin - * @param originZ the z coordinate of the ray's origin - * @param dirX the x coordinate of the ray's direction - * @param dirY the y coordinate of the ray's direction - * @param dirZ the z coordinate of the ray's direction - * @return true if this AABB and the ray intersect; false otherwise - */ - public boolean intersectsRay(float originX, float originY, float originZ, float dirX, float dirY, float dirZ) { - return Intersectionf.testRayAab( - originX, originY, originZ, dirX, dirY, dirZ, - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f - ); - } - - /** - * Test whether the given ray intersects this AABB. - *

- * This method returns true for a ray whose origin lies inside this AABB. - *

- * Reference: An Efficient and Robust Ray–Box Intersection - * - * @param ray the ray - * @return true if this AABB and the ray intersect; false otherwise - */ - public boolean intersectsRay(Rayf ray) { - return Intersectionf.testRayAab( - ray.oX, ray.oY, ray.oZ, ray.dX, ray.dY, ray.dZ, - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f - ); - } - - /** - * Determine whether the undirected line segment with the end points (p0X, p0Y, p0Z) and (p1X, - * p1Y, p1Z) intersects this AABB, and return the values of the parameter t in the ray equation - * p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection. - *

- * This method returns true for a line segment whose either end point lies inside this AABB. - *

- * Reference: An Efficient and Robust Ray–Box Intersection - * - * @param p0X the x coordinate of the line segment's first end point - * @param p0Y the y coordinate of the line segment's first end point - * @param p0Z the z coordinate of the line segment's first end point - * @param p1X the x coordinate of the line segment's second end point - * @param p1Y the y coordinate of the line segment's second end point - * @param p1Z the z coordinate of the line segment's second end point - * @param result a vector which will hold the resulting values of the parameter - * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection - * iff the line segment intersects this AABB - * @return {@link Intersectionf#INSIDE} if the line segment lies completely inside of this AABB; or {@link - * Intersectionf#OUTSIDE} if the line segment lies completely outside of this AABB; or {@link - * Intersectionf#ONE_INTERSECTION} if one of the end points of the line segment lies inside of this AABB; or - * {@link Intersectionf#TWO_INTERSECTION} if the line segment intersects two sides of this AABB or lies on - * an edge or a side of this AABB - */ - public int intersectLineSegment(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z, Vector2f result) { - return Intersectionf.intersectLineSegmentAab(p0X, p0Y, p0Z, p1X, p1Y, p1Z, - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, result); - - } + // ---------------------------------------------------------------------------------------------------------------// /** - * Determine whether the given undirected line segment intersects this AABB, and return the values of the parameter - * t in the ray equation - * p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection. - *

- * This method returns true for a line segment whose either end point lies inside this AABB. + * Compare this region to another object for equality. *

- * Reference: An Efficient and Robust Ray–Box Intersection - * - * @param lineSegment the line segment - * @param result a vector which will hold the resulting values of the parameter - * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection - * iff the line segment intersects this AABB - * @return {@link Intersectionf#INSIDE} if the line segment lies completely inside of this AABB; or {@link - * Intersectionf#OUTSIDE} if the line segment lies completely outside of this AABB; or {@link - * Intersectionf#ONE_INTERSECTION} if one of the end points of the line segment lies inside of this AABB; or - * {@link Intersectionf#TWO_INTERSECTION} if the line segment intersects two sides of this AABB or lies on - * an edge or a side of this AABB + * Two regions are equal iff their minimum and maximum corner are the equal. */ - public int intersectLineSegment(LineSegmentf lineSegment, Vector2f result) { - return Intersectionf.intersectLineSegmentAab( - lineSegment.aX, lineSegment.aY, lineSegment.aZ, lineSegment.bX, lineSegment.bY, lineSegment.bZ, - minX - .5f, - minY - .5f, - minZ - .5f, - maxX + .5f, - maxY + .5f, - maxZ + .5f, result); - } - @Override public boolean equals(Object obj) { if (this == obj) { @@ -1020,7 +528,7 @@ public int hashCode() { @Override public String toString() { - return "(" + this.minX + " " + this.minY + " " + this.minZ + ") < " + - "(" + (this.maxX - 1) + " " + (this.maxY - 1) + " " + (this.maxZ - 1) + ")"; + return "BlockRegion[(" + this.minX + " " + this.minY + " " + this.minZ + ")..." + + "(" + (this.maxX) + " " + (this.maxY) + " " + (this.maxZ) + ")]"; } } diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java b/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java deleted file mode 100644 index be2977b4007..00000000000 --- a/engine/src/main/java/org/terasology/world/block/BlockRegionIterable.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.world.block; - -import org.joml.Vector3i; -import org.joml.Vector3ic; - -import java.util.Iterator; - -public class BlockRegionIterable implements Iterable { - - private final BlockRegion region; - - BlockRegionIterable(BlockRegion region) { - this.region = region; - } - - @Override - public Iterator iterator() { - return new Iterator() { - private Vector3i current = null; - private final Vector3i next = region.getMin(new Vector3i()); - - public boolean findNext() { - if (current.equals(next)) { - next.z++; - if (next.z > region.maxZ()) { - next.z = region.minZ(); - next.y++; - if (next.y > region.maxY()) { - next.y = region.minY(); - next.x++; - } - } - return region.containsBlock(next); - } - return true; - } - - @Override - public boolean hasNext() { - if (!region.isValid()) { - return false; - } - if (current == null) { - return true; - } - - if (current.equals(next)) { - return findNext(); - } - return region.containsBlock(next); - } - - @Override - public Vector3ic next() { - if (current == null) { - current = new Vector3i(next); - return next; - } - - if (current.equals(next)) { - if (findNext()) { - return next; - } - return null; - } - current.set(next); - return next; - } - }; - } -} diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegionc.java b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java new file mode 100644 index 00000000000..f582ad6071d --- /dev/null +++ b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java @@ -0,0 +1,786 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.world.block; + +import org.joml.AABBf; +import org.joml.Intersectionf; +import org.joml.LineSegmentf; +import org.joml.Matrix4fc; +import org.joml.Planef; +import org.joml.Rayf; +import org.joml.Spheref; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.joml.Vector3i; +import org.joml.Vector3ic; + +import java.util.Iterator; +import java.util.Optional; + +/** + * An immutable, bounded, axis-aligned volume in space denoting a collection of blocks contained within. + */ +public interface BlockRegionc extends Iterable { + + // -- ITERABLE ---------------------------------------------------------------------------------------------------// + + /** + * Iterate over the blocks in the block region, where the same {@link Vector3ic} is reused for low memory + * footprint. + *

+ * Do not store the elements directly or use them outside the context of the iterator as they will change when the + * iterator is advanced. You may create new vectors from the elements if necessary, e.g.: + *

+     *     for (Vector3ic p : region) {
+     *         Vector3i pos = new Vector3i(p);
+     *         // use 'pos' instead of 'p'
+     *     }
+     * 
+ */ + Iterator iterator(); + + // -- min -------------------------------------------------------------------------------------------------------// + + /** + * The x-coordinate of the minimum corner + */ + int minX(); + + /** + * The y-coordinate of the minimum corner + */ + int minY(); + + /** + * The z-coordinate of the minimum corner + */ + int minZ(); + + /** + * Get the block coordinate of the minimum corner. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector3i getMin(Vector3i dest) { + return dest.set(minX(), minY(), minZ()); + } + + /** + * Set the minimum x-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is greater than the maximum x coordinate + */ + BlockRegion minX(int x, BlockRegion dest); + + /** + * Set the minimum y-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code y} is greater than the maximum y coordinate + */ + BlockRegion minY(int y, BlockRegion dest); + + /** + * Set the minimum z-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code z} is greater than the maximum z coordinate + */ + BlockRegion minZ(int z, BlockRegion dest); + + /** + * Set the coordinates of the minimum corner for this region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is greater than the respective component of the maximum + * corner + */ + BlockRegion setMin(int x, int y, int z, BlockRegion dest); + + /** + * Set the coordinates of the minimum corner for this region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is greater than the respective component of the maximum + * corner + */ + default BlockRegion setMin(Vector3ic min, BlockRegion dest) { + return this.setMin(min.x(), min.y(), min.z(), dest); + } + + /** + * Translate the minimum corner of the region by adding given {@code (dx, dy, dz)}. + * + * @param dx the number of blocks to add to the minimum corner on the x axis + * @param dy the number of blocks to add to the minimum corner on the y axis + * @param dz the number of blocks to add to the minimum corner on the z axis + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting region would be {@link #isValid() invalid}. + */ + default BlockRegion addToMin(int dx, int dy, int dz, BlockRegion dest) { + return this.setMin(minX() + dx, minY() + dy, minZ() + dz, dest); + } + + /** + * Translate the minimum corner of the region by adding given {@code (dx, dy, dz)}. + * + * @param dmin the translation vector for the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting region would be {@link #isValid() invalid}. + */ + default BlockRegion addToMin(Vector3ic dmin, BlockRegion dest) { + return this.addToMin(dmin.x(), dmin.y(), dmin.z(), dest); + } + + // -- max -------------------------------------------------------------------------------------------------------// + + /** + * The x-coordinate of the maximum corner + */ + int maxX(); + + /** + * The y-coordinate of the maximum corner + */ + int maxY(); + + /** + * The z-coordinate of the maximum corner + */ + int maxZ(); + + /** + * Get the block coordinate of the maximum corner. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector3i getMax(Vector3i dest) { + return dest.set(maxX(), maxY(), maxZ()); + } + + /** + * Set the maximum x-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is smaller than the minimum x-coordinate + */ + BlockRegion maxX(int x, BlockRegion dest); + + /** + * Set the maximum y-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is smaller than the minimum x-coordinate + */ + BlockRegion maxY(int y, BlockRegion dest); + + /** + * Set the maximum z-coordinate of the region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is smaller than the minimum x-coordinate + */ + BlockRegion maxZ(int z, BlockRegion dest); + + /** + * Set the coordinates of the maximum corner for this region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is smaller than the respective component of the minimum + * corner + */ + BlockRegion setMax(int x, int y, int z, BlockRegion dest); + + /** + * Set the coordinates of the maximum corner for this region. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is smaller than the respective component of the minimum + * corner + */ + default BlockRegion setMax(Vector3ic max, BlockRegion dest) { + return this.setMax(max.x(), max.y(), max.z(), dest); + } + + /** + * Translate the maximum corner of the region by adding given {@code (dx, dy, dz)}. + * + * @param dx the number of blocks to add to the maximum corner on the x axis + * @param dy the number of blocks to add to the maximum corner on the y axis + * @param dz the number of blocks to add to the maximum corner on the z axis + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting region would be {@link #isValid() invalid}. + */ + default BlockRegion addToMax(int dx, int dy, int dz, BlockRegion dest) { + return this.setMax(maxX() + dx, maxY() + dy, maxZ() + dz, dest); + } + + /** + * Translate the maximum corner of the region by adding given {@code (dx, dy, dz)}. + * + * @param dmax the translation vector for the maximum corner + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting region would be {@link #isValid() invalid}. + */ + default BlockRegion addToMax(Vector3ic dmax, BlockRegion dest) { + return this.addToMax(dmax.x(), dmax.y(), dmax.z(), dest); + } + + // -- size ------------------------------------------------------------------------------------------------------// + + /** + * The number of blocks on the x axis. + */ + default int getSizeX() { + return maxX() - minX() + 1; + } + + /** + * The number of blocks on the y axis. + */ + default int getSizeY() { + return maxY() - minY() + 1; + } + + /** + * The number of blocks on the z axis. + */ + default int getSizeZ() { + return maxZ() - minZ() + 1; + } + + /** + * The number of blocks in this region along the +x, +y, +z axis from the minimum to the maximum corner. + * + * @param dest will hold the result + * @return dest + */ + default Vector3i getSize(Vector3i dest) { + return dest.set(getSizeX(), getSizeY(), getSizeZ()); + } + + /** + * Set the size of the block region from the minimum corner. + * + * @param x the x coordinate to set the size; must be > 0 + * @param y the y coordinate to set the size; must be > 0 + * @param z the z coordinate to set the size; must be > + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the size is smaller than or equal to 0 in any dimension + */ + BlockRegion setSize(int x, int y, int z, BlockRegion dest); + + /** + * Set the size of the block region from the minimum corner. + * + * @param size the size to set; all dimensions must be > 0 + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the size is smaller than or equal to 0 in any dimension + */ + default BlockRegion setSize(Vector3ic size, BlockRegion dest) { + return this.setSize(size.x(), size.y(), size.z(), dest); + } + + /** + * The volume of this region in blocks, i.e., the number of blocks contained in this region. + *

+ * The volume is computed by + *

+     *     volume = sizeX * sizeY * sizeZ;
+     * 
+ * + * @return the volume in blocks + */ + default int volume() { + return getSizeX() * getSizeY() * getSizeZ(); + } + + // -- world -----------------------------------------------------------------------------------------------------// + + /** + * The bounding box in world coordinates. + *

+ * The bounding box of a single block at {@code (x, y, z)} is centered at the integer coordinate {@code (x, y, z)} + * and extents by {@code 0.5} in each dimension. + * + * @param dest will hold the result + * @return {@code dest} + */ + //TODO: 1.9.26 has a constant interface for aabbf + default AABBf getBounds(AABBf dest) { + dest.minX = minX() - .5f; + dest.minY = minY() - .5f; + dest.minZ = minZ() - .5f; + + dest.maxX = maxX() + .5f; + dest.maxY = maxY() + .5f; + dest.maxZ = maxZ() + .5f; + + return dest; + } + + /** + * The center of the region in world coordinates if the region is valid; {@link Float#NaN} otherwise. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector3f center(Vector3f dest) { + if (!this.isValid()) { + return dest.set(Float.NaN); + } + return dest.set( + (this.minX() - .5f) + ((this.maxX() - this.minX() + 1.0f) / 2.0f), + (this.minY() - .5f) + ((this.maxY() - this.minY() + 1.0f) / 2.0f), + (this.minZ() - .5f) + ((this.maxZ() - this.minZ() + 1.0f) / 2.0f) + ); + } + + // -- IN-PLACE MUTATION -----------------------------------------------------------------------------------------// + // -- union -----------------------------------------------------------------------------------------------------// + + /** + * Compute the union of this region and the given block coordinate. + * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + BlockRegion union(int x, int y, int z, BlockRegion dest); + + /** + * Compute the union of this region and the given block coordinate. + * + * @param pos the position of the block + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockRegion union(Vector3ic pos, BlockRegion dest) { + return this.union(pos.x(), pos.y(), pos.z(), dest); + } + + /** + * Compute the union of this region and the other region. + * + * @param other {@link BlockRegion} + * @param dest destination; will hold the result + * @return @code dest} (after modification) + */ + default BlockRegion union(BlockRegionc other, BlockRegion dest) { + return this.union(other.minX(), other.minY(), other.minZ(), dest) + .union(other.maxX(), other.maxY(), other.maxZ(), dest); + } + + // -- intersect -------------------------------------------------------------------------------------------------// + + /** + * Compute the intersection of this region with the {@code other} region. + *

+ * NOTE: If the regions don't intersect the destination region will become invalid! + * + * @param other the other region + * @param dest destination; will hold the result + * @return {@code dest} (after modification) or {@link Optional#empty()} if the regions don't intersect + */ + Optional intersect(BlockRegionc other, BlockRegion dest); + + // ---------------------------------------------------------------------------------------------------------------// + + /** + * Translate this region by the given vector {@code (x, y, z))}. + * + * @param dx the x coordinate to translate by + * @param dy the y coordinate to translate by + * @param dz the z coordinate to translate by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + BlockRegion translate(int dx, int dy, int dz, BlockRegion dest); + + /** + * Translate this region by the given vector {@code vec}. + * + * @param vec the vector to translate by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockRegion translate(Vector3ic vec, BlockRegion dest) { + return this.translate(vec.x(), vec.y(), vec.z(), dest); + } + + /** + * Move this region to the given position {@code (x, y, z)). The position is defined by the minimum corner. + * + * @param x the new x coordinate of the minimum corner + * @param y the new y coordinate of the minimum corner + * @param z the new z coordinate of the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockRegion setPosition(int x, int y, int z, BlockRegion dest) { + return dest.translate(x - this.minX(), y - this.minY(), z - this.minZ()); + } + + /** + * Move this region to the given position {@code (x, y, z)). The position is defined by the minimum corner. + * + * @param pos the new coordinates of the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockRegion setPosition(Vector3ic pos, BlockRegion dest) { + return setPosition(pos.x(), pos.y(), pos.z(), dest); + } + + // -- expand -----------------------------------------------------------------------------------------------------// + + /** + * Expand this region by adding the given {@code extents} for each face of the region. + * + * @param dx the amount of blocks to extend this region by along the x axis in both directions + * @param dy the amount of blocks to extend this region by along the y axis in both directions + * @param dz the amount of blocks to extend this region by along the z axis in both directions + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if extending this region would result in any non-positive dimension + */ + BlockRegion expand(int dx, int dy, int dz, BlockRegion dest); + + /** + * Expand this region by adding the given {@code extents} for each face of a region. + * + * @param vec the amount of blocks to expand this region by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if extending this region would result in any non-positive dimension + */ + default BlockRegion expand(Vector3ic vec, BlockRegion dest) { + return this.expand(vec.x(), vec.y(), vec.z(), dest); + } + + // -- transform --------------------------------------------------------------------------------------------------// + + /** + * Apply the given {@link Matrix4fc#isAffine() affine} transformation to this {@link BlockRegion}. + *

+ * The matrix in {@code m} must be {@link Matrix4fc#isAffine() affine}. + * + * @param m the affine transformation matrix + * @param dest will hold the result + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the matrix {@code m} is not {@link Matrix4fc#isAffine() affine} + */ + BlockRegion transform(Matrix4fc m, BlockRegion dest); + + // -- CHECKS -----------------------------------------------------------------------------------------------------// + + /** + * Check whether this region BlockRegion represents a valid BlockRegion. + * + * @return {@code true} iff this BlockRegion is valid; {@code false} otherwise + */ + default boolean isValid() { + return minX() <= maxX() && minY() <= maxY() && minZ() <= maxZ(); + } + + // -- contains ---------------------------------------------------------------------------------------------------// + + /** + * Test whether the block {@code (x, y, z)} lies inside this region. + * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + * @return {@code true} iff the given point lies inside this region; {@code false} otherwise + */ + default boolean contains(int x, int y, int z) { + return x >= minX() && y >= minY() && z >= minZ() && x <= maxX() && y <= maxY() && z <= maxZ(); + } + + /** + * Test whether the block at position {@code pos} lies inside this region. + * + * @param pos the coordinates of the block + * @return {@code true} iff the given point lies inside this region; {@code false} otherwise + */ + default boolean contains(Vector3ic pos) { + return this.contains(pos.x(), pos.y(), pos.z()); + } + + /** + * Test whether the point {@code (x, y, z)} lies inside this region. + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @param z the z coordinate of the point + * @return {@code true} iff the given point lies inside this region; {@code false} otherwise + * @see #getBounds(AABBf) + */ + default boolean contains(float x, float y, float z) { + return x >= (this.minX() - .5f) + && y >= (this.minY() - .5f) + && z >= (this.minZ() - .5f) + && x <= (this.maxX() + .5f) + && y <= (this.maxY() + .5f) + && z <= (this.maxZ() + .5f); + } + + /** + * Test whether the {@code point} lies inside this region. + * + * @param point the coordinates of the point + * @return {@code true} iff the given point lies inside this region; {@code false} otherwise + */ + default boolean contains(Vector3fc point) { + return this.contains(point.x(), point.y(), point.z()); + } + + /** + * Test whether the given region {@code other} is fully enclosed by this region. + * + * @param other the other region + * @return {@code true} iff the given region is fully enclosed by this region; {@code false} otherwise + */ + default boolean contains(BlockRegionc other) { + return this.contains(other.minX(), other.minY(), other.minZ()) + && this.contains(other.maxX(), other.maxY(), other.maxZ()); + } + + // -- intersects -------------------------------------------------------------------------------------------------// + + /** + * Test whether this region and the AABB {@code other} intersect. + * + * @param other the other AABB + * @return {@code true} iff both AABBs intersect; {@code false} otherwise + */ + default boolean intersectsAABB(AABBf other) { + return Intersectionf.testAabAab( + this.minX() - .5f, this.minY() - .5f, this.minZ() - .5f, + this.maxX() + .5f, this.maxY() + .5f, this.maxZ() + .5f, + other.minX, other.minY, other.minZ, + other.maxX, other.maxY, other.maxZ + ); + } + + /** + * Test whether this region and {@code other} intersect. + * + * @param other the other BlockRegion + * @return {@code true} iff both regions intersect; {@code false} otherwise + */ + default boolean intersectsBlockRegion(BlockRegionc other) { + return this.maxX() >= other.minX() && this.maxY() >= other.minY() && this.maxZ() >= other.minZ() + && this.minX() <= other.maxX() && this.minY() <= other.maxY() && this.minZ() <= other.maxZ(); + } + + /** + * Test whether the plane given via its plane equation a*x + b*y + c*z + d = 0 intersects this region. + *

+ * Reference: + * http://www.lighthouse3d.com + * ("Geometric Approach - Testing Boxes II") + * + * @param a the x factor in the plane equation + * @param b the y factor in the plane equation + * @param c the z factor in the plane equation + * @param d the constant in the plane equation + * @return {@code true} iff the plane intersects this region; {@code false} otherwise + */ + default boolean intersectsPlane(float a, float b, float c, float d) { + return Intersectionf.testAabPlane( + minX() - .5f, + minY() - .5f, + minZ() - .5f, + maxX() + .5f, + maxY() + .5f, + maxZ() + .5f, a, b, c, d); + } + + /** + * Test whether the given plane intersects this region. + *

+ * Reference: + * http://www.lighthouse3d.com + * ("Geometric Approach - Testing Boxes II") + * + * @param plane the plane + * @return {@code true} iff the plane intersects this region; {@code false} otherwise + */ + default boolean intersectsPlane(Planef plane) { + return this.intersectsPlane(plane.a, plane.b, plane.c, plane.d); + } + + /** + * Test whether the given ray with the origin (originX, originY, originZ) and direction (dirX, + * dirY, dirZ) intersects this AABB. + *

+ * This method returns {@code true} for a ray whose origin lies inside this region. + *

+ * Reference: An Efficient and Robust Ray–Box Intersection + * + * @param originX the x coordinate of the ray's origin + * @param originY the y coordinate of the ray's origin + * @param originZ the z coordinate of the ray's origin + * @param dirX the x coordinate of the ray's direction + * @param dirY the y coordinate of the ray's direction + * @param dirZ the z coordinate of the ray's direction + * @return {@code true} if this region and the ray intersect; {@code false} otherwise + */ + default boolean intersectsRay(float originX, float originY, float originZ, float dirX, float dirY, float dirZ) { + return Intersectionf.testRayAab( + originX, originY, originZ, dirX, dirY, dirZ, + minX() - .5f, + minY() - .5f, + minZ() - .5f, + maxX() + .5f, + maxY() + .5f, + maxZ() + .5f + ); + } + + /** + * Test whether the given ray intersects this region. + *

+ * This method returns {@code true} for a ray whose origin lies inside this region. + *

+ * Reference: An Efficient and Robust Ray–Box Intersection + * + * @param ray the ray + * @return {@code true} if this AABB and the ray intersect; {@code false} otherwise + */ + default boolean intersectsRay(Rayf ray) { + return this.intersectsRay(ray.oX, ray.oY, ray.oZ, ray.dX, ray.dY, ray.dZ); + } + + /** + * Test whether this region intersects the given sphere with equation + * (x - centerX)^2 + (y - centerY)^2 + (z - centerZ)^2 - radiusSquared = 0. + *

+ * Reference: + * http://stackoverflow.com + * + * @param centerX the x coordinate of the center of the sphere + * @param centerY the y coordinate of the center of the sphere + * @param centerZ the z coordinate of the center of the sphere + * @param radiusSquared the square radius of the sphere + * @return {@code true} iff this region and the sphere intersect; {@code false} otherwise + */ + default boolean intersectsSphere(float centerX, float centerY, float centerZ, float radiusSquared) { + return Intersectionf.testAabSphere( + minX() - .5f, + minY() - .5f, + minZ() - .5f, + maxX() + .5f, + maxY() + .5f, + maxZ() + .5f, + centerX, + centerY, + centerZ, + radiusSquared + ); + } + + /** + * Test whether this region intersects the given sphere. + *

+ * Reference: + * http://stackoverflow.com + * + * @param sphere the sphere + * @return {@code true} iff this region and the sphere intersect; {@code false} otherwise + */ + default boolean intersectsSphere(Spheref sphere) { + return this.intersectsSphere(sphere.x, sphere.y, sphere.z, sphere.r * sphere.r); + } + + /** + * Determine whether the undirected line segment with the end points (p0X, p0Y, p0Z) and (p1X, + * p1Y, p1Z) intersects this region, and return the values of the parameter t in the ray equation + * p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection. + *

+ * This method returns {@code true} for a line segment whose either end point lies inside this AABB. + *

+ * Reference: An Efficient and Robust Ray–Box Intersection + * + * @param p0X the x coordinate of the line segment's first end point + * @param p0Y the y coordinate of the line segment's first end point + * @param p0Z the z coordinate of the line segment's first end point + * @param p1X the x coordinate of the line segment's second end point + * @param p1Y the y coordinate of the line segment's second end point + * @param p1Z the z coordinate of the line segment's second end point + * @param result a vector which will hold the resulting values of the parameter + * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection + * iff the line segment intersects this AABB + * @return {@link Intersectionf#INSIDE} if the line segment lies completely inside of this AABB; or {@link + * Intersectionf#OUTSIDE} if the line segment lies completely outside of this AABB; or {@link + * Intersectionf#ONE_INTERSECTION} if one of the end points of the line segment lies inside of this AABB; or + * {@link Intersectionf#TWO_INTERSECTION} if the line segment intersects two sides of this AABB or lies on + * an edge or a side of this AABB + */ + default int intersectLineSegment(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z, + Vector2f result) { + return Intersectionf.intersectLineSegmentAab(p0X, p0Y, p0Z, p1X, p1Y, p1Z, + minX() - .5f, + minY() - .5f, + minZ() - .5f, + maxX() + .5f, + maxY() + .5f, + maxZ() + .5f, result); + } + + /** + * Determine whether the given undirected line segment intersects this region, and return the values of the + * parameter + * t in the ray equation + * p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection. + *

+ * This method returns {@code true} for a line segment whose either end point lies inside this regiono. + *

+ * Reference: An Efficient and Robust Ray–Box Intersection + * + * @param lineSegment the line segment + * @param result a vector which will hold the resulting values of the parameter + * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection + * iff the line segment intersects this AABB + * @return {@link Intersectionf#INSIDE} if the line segment lies completely inside of this AABB; or {@link + * Intersectionf#OUTSIDE} if the line segment lies completely outside of this AABB; or {@link + * Intersectionf#ONE_INTERSECTION} if one of the end points of the line segment lies inside of this AABB; or + * {@link Intersectionf#TWO_INTERSECTION} if the line segment intersects two sides of this AABB or lies on + * an edge or a side of this AABB + */ + default int intersectLineSegment(LineSegmentf lineSegment, Vector2f result) { + return this.intersectLineSegment(lineSegment.aX, lineSegment.aY, lineSegment.aZ, + lineSegment.bX, lineSegment.bY, lineSegment.bZ, + result); + } + + // ---------------------------------------------------------------------------------------------------------------// + public boolean equals(Object obj); + + public int hashCode(); + + public String toString(); +} diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegions.java b/engine/src/main/java/org/terasology/world/block/BlockRegions.java deleted file mode 100644 index fa6faaa8502..00000000000 --- a/engine/src/main/java/org/terasology/world/block/BlockRegions.java +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2020 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.world.block; - -import org.joml.RoundingMode; -import org.joml.Vector3f; -import org.joml.Vector3fc; -import org.joml.Vector3i; -import org.joml.Vector3ic; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -public final class BlockRegions { - private BlockRegions() { - } - - /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. - *

- * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If - * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region - * will have a size of 0 along that dimension. - *

- * Consider using {@link #encompassing(Vector3ic...)} as an alternative. - * - * @return new block region - */ - public static BlockRegion createFromMinAndMax(Vector3ic min, Vector3ic max) { - return new BlockRegion(min, max); - } - - /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. - *

- * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If - * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region - * will have a size of 0 along that dimension. - *

- * Consider using {@link #encompassing(Vector3ic...)} as an alternative. - * - * @return new block region - */ - public static BlockRegion createFromMinAndMax(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - return new BlockRegion(minX, minY, minZ, maxX, maxY, maxZ); - } - - /** - * Creates a new region centered around {@code center} extending each side by {@code extents}. The resulting - * axis-aligned bounding box (AABB) will have a size of {@code 2 * extents} - * - * @return new block region - */ - public static BlockRegion createFromCenterAndExtents(Vector3ic center, Vector3ic extents) { - return new BlockRegion(center).extend(extents); - } - - /** - * Creates a new region centered around {@code center} extending each side by {@code extents}. The computed min is - * rounded up (ceil), the computed max is rounded down (floor). Thus, the resulting axis-aligned bounding box (AABB) - * will only include integer points that are within the floating point area and have a size of {@code <= 2 * - * extents} - * - * @return new block region - */ - public static BlockRegion createFromCenterAndExtents(Vector3fc center, Vector3fc extents) { - Vector3f min = center.sub(extents, new Vector3f()); - Vector3f max = center.add(extents, new Vector3f()); - - return new BlockRegion(new Vector3i(min, RoundingMode.CEILING), new Vector3i(max, RoundingMode.FLOOR)); - } - - /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing both, min and max. - *

- * Note that each component of {@code min} should be smaller or equal to the respective component in {@code max}. If - * a dimension of {@code min} is greater than the respective dimension of {@code max} the resulting block region - * will have a size of 0 along that dimension. - *

- * Consider using {@link #encompassing(Vector3ic, Vector3ic...)} as an alternative. - * - * @return new block region - */ - public static BlockRegion createFromMinAndSize(Vector3ic min, Vector3ic size) { - return new BlockRegion(min).setSize(size); - } - - public static BlockRegion encompassing(Stream positions) { - return positions.reduce(new BlockRegion(), BlockRegion::union, BlockRegion::union); - } - - /** - * Creates a new region spanning the smallest axis-aligned bounding box (AABB) containing all the given positions. - * - * @param positions the positions that must be contained in the resulting block region - * @return a new block region containing all given positions - */ - public static BlockRegion encompassing(Vector3ic first, Vector3ic... positions) { - return encompassing(Stream.concat(Stream.of(first), Arrays.stream(positions))); - } - - public static BlockRegion encompassing(Iterable positions) { - return encompassing(StreamSupport.stream(positions.spliterator(), false)); - } - - public static BlockRegion encompassing(Collection positions) { - return encompassing(positions.stream()); - } - - /** - * An iterable over the blocks in the block region, where each position is wrapped in a new {@link Vector3i}. - *

- * If you only need the elements of the block region in the local context of the iterator step without modifications - * you may want to consider using {@link #iterableInPlace(BlockRegion)} instead. - * - * @param region the region to iterate over - */ - public static Iterable iterable(BlockRegion region) { - return () -> { - Iterator itr = iterableInPlace(region).iterator(); - return new Iterator() { - @Override - public boolean hasNext() { - return itr.hasNext(); - } - - @Override - public Vector3i next() { - return new Vector3i(itr.next()); - } - }; - }; - } - - /** - * An iterable over the blocks in the block region, where the same {@link Vector3ic} is reused to avoid GC. - *

- * Use this iterable for performance optimized iterations where the positions are only needed within the context of - * the iterator sequence. - *

- * Do not store the elements directly or use them outside the context of the iterator as they will change when the - * iterator is advanced. You may create new vectors from the elements if necessary, or use {@link - * #iterable(BlockRegion)} instead. - * - * @param region the region to iterate over - */ - public static Iterable iterableInPlace(BlockRegion region) { - return new BlockRegionIterable(region); - } -} diff --git a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java index a619182a5df..cb9023d7d6a 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java @@ -41,7 +41,6 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.block.BlockManager; -import org.terasology.world.block.BlockRegions; import org.terasology.world.block.entity.damage.BlockDamageModifierComponent; import org.terasology.world.block.items.BlockItemFactory; import org.terasology.world.block.items.OnBlockToItem; @@ -105,7 +104,7 @@ public void defaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, BlockRegionComponent blockRegion = entity.getComponent(BlockRegionComponent.class); if (blockComponent.dropBlocksInRegion) { // loop through all the blocks in this region and drop them - for (Vector3ic location : BlockRegions.iterableInPlace(blockRegion.region)) { + for (Vector3ic location : blockRegion.region) { Block blockInWorld = worldProvider.getBlock(location); commonDefaultDropsHandling(event, entity, JomlUtil.from(location), blockInWorld.getBlockFamily().getArchetypeBlock()); } diff --git a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java index 491b410c6eb..c2f94dd71e8 100644 --- a/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java +++ b/engine/src/main/java/org/terasology/world/block/regions/BlockRegionSystem.java @@ -13,7 +13,6 @@ import org.terasology.registry.In; import org.terasology.world.WorldProvider; import org.terasology.world.block.BlockManager; -import org.terasology.world.block.BlockRegions; /** */ @@ -29,7 +28,7 @@ public class BlockRegionSystem extends BaseComponentSystem { // trivial priority so that all other logic can happen to the region before erasing the blocks in the region @ReceiveEvent(priority = EventPriority.PRIORITY_TRIVIAL) public void onDestroyed(DoDestroyEvent event, EntityRef entity, BlockRegionComponent blockRegion) { - for (Vector3ic blockPosition : BlockRegions.iterableInPlace(blockRegion.region)) { + for (Vector3ic blockPosition : blockRegion.region) { worldProvider.setBlock(blockPosition, blockManager.getBlock(BlockManager.AIR_ID)); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index dfc2482215a..af3de36684c 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -31,7 +31,7 @@ import org.terasology.world.block.BeforeDeactivateBlocks; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; -import org.terasology.world.block.BlockRegions; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.OnActivatedBlocks; import org.terasology.world.block.OnAddedBlocks; import org.terasology.world.chunks.Chunk; @@ -449,10 +449,7 @@ public void purgeWorld() { Chunk[] localchunks = chunks.toArray(new Chunk[0]); return new LightMerger().merge(localchunks); }, - pos -> StreamSupport.stream(BlockRegions.iterableInPlace(BlockRegions.createFromMinAndMax( - pos.x() - 1, pos.y() - 1, pos.z() - 1, - pos.x() + 1, pos.y() + 1, pos.z() + 1 - )).spliterator(), false) + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1,1,1).spliterator(), false) .map(org.joml.Vector3i::new) .collect(Collectors.toSet()) )) @@ -490,10 +487,7 @@ public void setRelevanceSystem(RelevanceSystem relevanceSystem) { Chunk[] localchunks = chunks.toArray(new Chunk[0]); return new LightMerger().merge(localchunks); }, - pos -> StreamSupport.stream(BlockRegions.iterableInPlace(BlockRegions.createFromMinAndMax( - pos.x() - 1, pos.y() - 1, pos.z() - 1, - pos.x() + 1, pos.y() + 1, pos.z() + 1 - )).spliterator(), false) + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1,1,1).spliterator(), false) .map(org.joml.Vector3i::new) .collect(Collectors.toCollection(Sets::newLinkedHashSet)) )) diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index f5da90ca5c3..3a280979ff3 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -18,8 +18,6 @@ import org.terasology.monitoring.chunk.ChunkMonitor; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegionIterable; -import org.terasology.world.block.BlockRegions; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; @@ -77,10 +75,7 @@ public RemoteChunkProvider(BlockManager blockManager, LocalPlayer localPlayer) { Chunk[] localchunks = chunks.toArray(new Chunk[0]); return new LightMerger().merge(localchunks); }, - pos -> StreamSupport.stream(BlockRegions.iterableInPlace(BlockRegions.createFromMinAndMax( - pos.x() - 1, pos.y() - 1, pos.z() - 1, - pos.x() + 1, pos.y() + 1, pos.z() + 1 - )).spliterator(), false) + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1, 1, 1).spliterator(), false) .map(org.joml.Vector3i::new) .collect(Collectors.toSet()) )) diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index ea9debca8dc..4a607d02b6d 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -56,7 +56,6 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; import org.terasology.world.block.regions.BlockRegionComponent; import java.math.RoundingMode; @@ -475,28 +474,28 @@ public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) public void onBlockRegionActivated(OnActivatedComponent event, EntityRef entity) { BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (org.joml.Vector3i pos : BlockRegions.iterable(regionComp.region)) { - blockRegionLookup.put(pos, entity); + for (org.joml.Vector3ic pos : regionComp.region) { + blockRegionLookup.put(new org.joml.Vector3i(pos), entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionChanged(OnChangedComponent event, EntityRef entity) { BlockRegion oldRegion = blockRegions.get(entity); - for (org.joml.Vector3ic pos : BlockRegions.iterableInPlace(oldRegion)) { + for (org.joml.Vector3ic pos : oldRegion) { blockRegionLookup.remove(pos); } BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (org.joml.Vector3i pos : BlockRegions.iterable(regionComp.region)) { - blockRegionLookup.put(pos, entity); + for (org.joml.Vector3ic pos : regionComp.region) { + blockRegionLookup.put(new org.joml.Vector3i(pos), entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionDeactivated(BeforeDeactivateComponent event, EntityRef entity) { BlockRegion oldRegion = blockRegions.get(entity); - for (org.joml.Vector3ic pos : BlockRegions.iterableInPlace(oldRegion)) { + for (org.joml.Vector3ic pos : oldRegion) { blockRegionLookup.remove(pos); } blockRegions.remove(entity); diff --git a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java index e0d66b08854..317fe8ccd0f 100644 --- a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java @@ -24,7 +24,6 @@ import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; -import org.terasology.world.block.BlockRegions; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.LitChunk; @@ -304,11 +303,11 @@ private void cleanUp() { public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boolean propagateExternal) { IndexProvider indexProvider = createIndexProvider(side); - BlockRegion edgeRegion = BlockRegions.createFromMinAndSize(new org.joml.Vector3i(0, 0, 0), JomlUtil.from(ChunkConstants.CHUNK_SIZE)); + BlockRegion edgeRegion = new BlockRegion(0, 0, 0) + .setSize(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); ChunkMath.getEdgeRegion(edgeRegion, side, edgeRegion); - int edgeSize = edgeRegion.sizeX() * edgeRegion.sizeY() * edgeRegion.sizeZ(); - int[] depth = new int[edgeSize]; + int[] depth = new int[edgeRegion.volume()]; propagateSide(chunk, adjChunk, side, indexProvider, edgeRegion, depth); propagateDepth(adjChunk, side, propagateExternal, indexProvider, edgeRegion, depth); @@ -334,7 +333,7 @@ private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExter } } - for (Vector3ic pos : BlockRegions.iterableInPlace(edgeRegion)) { + for (Vector3ic pos : edgeRegion) { int depthIndex = indexProvider.getIndexFor(JomlUtil.from(pos)); int adjacentDepth = adjDepth[depthIndex]; for (int i = adjacentDepth; i < depths[depthIndex]; ++i) { @@ -353,9 +352,9 @@ private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExter private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, IndexProvider indexProvider, BlockRegion edgeRegion, int[] depths) { Vector3i adjPos = new Vector3i(); - for (int x = edgeRegion.getMinX(); x <= edgeRegion.getMaxX(); ++x) { - for (int y = edgeRegion.getMinY(); y <= edgeRegion.getMaxY(); ++y) { - for (int z = edgeRegion.getMinZ(); z <= edgeRegion.getMaxZ(); ++z) { + for (int x = edgeRegion.minX(); x <= edgeRegion.maxX(); ++x) { + for (int y = edgeRegion.minY(); y <= edgeRegion.maxY(); ++y) { + for (int z = edgeRegion.minZ(); z <= edgeRegion.maxZ(); ++z) { byte expectedValue = (byte) (rules.getValue(chunk, x, y, z) - 1); if (expectedValue < 1) { From 3647f301b4e2b47bb3301ca95de61d3e212abc4e Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 25 Dec 2020 09:00:20 -0800 Subject: [PATCH 039/259] chore(gradle): remove mavenLocal from project repositories (#4330) superceded by gradle Included Builds. See https://docs.gradle.org/6.7.1/userguide/declaring_repositories.html#sec:case-for-maven-local --- build.gradle | 1 - config/gradle/common.gradle | 20 ++------------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index f2831d6a9cc..1cc820e4f25 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,6 @@ repositories { // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case jcenter() mavenCentral() - mavenLocal() // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs maven { diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index 68ad796326f..926387290a1 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 // language apply plugin: 'java' @@ -40,9 +27,6 @@ tasks.withType(JavaCompile) { // We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on repositories { - // For development so you can publish binaries locally and have them grabbed from there - mavenLocal() - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case jcenter() mavenCentral() From ea2f56c37677902fbcfb7d48e95ee0007b2f6bdc Mon Sep 17 00:00:00 2001 From: jdrueckert Date: Sat, 26 Dec 2020 20:13:02 +0100 Subject: [PATCH 040/259] feat(JOML): migrate world gen (#4322) Co-authored-by: Tobias Nett --- .../java/org/terasology/MapWorldProvider.java | 3 +- .../testUtil/WorldProviderCoreStub.java | 3 +- .../Zones/LayeredZoneRegionFunctionTest.java | 5 +- .../world/generation/WorldBuilderTest.java | 27 +++++---- .../facets/BaseBooleanFacetTest.java | 3 +- .../generation/facets/BaseFieldFacetTest.java | 4 +- .../facets/BaseObjectFacetTest.java | 3 +- .../generation/facets/BooleanFacetTest.java | 8 +-- .../generation/facets/FieldFacetTest.java | 8 +-- .../generation/facets/ObjectFacetTest.java | 8 +-- .../facets/SparseBooleanFacetTest.java | 6 +- .../facets/SparseFieldFacetTest.java | 6 +- .../facets/SparseObjectFacetTest.java | 6 +- .../logic/spawner/AbstractSpawner.java | 6 +- .../mainMenu/preview/FacetLayerPreview.java | 12 ++-- .../utilities/procedural/SubSampledNoise.java | 57 +++++++++---------- .../terasology/world/chunks/CoreChunk.java | 3 +- .../world/chunks/internal/ChunkImpl.java | 40 ++++++------- .../terasology/world/generation/Border3D.java | 24 ++++---- .../world/generation/GeneratingRegion.java | 4 +- .../terasology/world/generation/Region.java | 4 +- .../world/generation/RegionImpl.java | 7 ++- .../terasology/world/generation/World.java | 3 +- .../world/generation/WorldFacet3D.java | 5 +- .../world/generation/WorldImpl.java | 3 +- .../world/generation/facets/DensityFacet.java | 3 +- .../generation/facets/ElevationFacet.java | 3 +- .../generation/facets/SeaLevelFacet.java | 4 +- .../generation/facets/SpawnHeightFacet.java | 4 +- .../facets/StrictlySparseSeaLevelFacet.java | 4 +- .../generation/facets/SurfaceDepthFacet.java | 3 +- .../facets/SurfaceHumidityFacet.java | 4 +- .../facets/SurfaceTemperatureFacet.java | 4 +- .../generation/facets/SurfacesFacet.java | 4 +- .../facets/base/BaseBooleanFieldFacet2D.java | 5 +- .../facets/base/BaseBooleanFieldFacet3D.java | 25 ++++---- .../generation/facets/base/BaseFacet2D.java | 6 +- .../generation/facets/base/BaseFacet3D.java | 23 ++++---- .../facets/base/BaseFieldFacet2D.java | 3 +- .../facets/base/BaseFieldFacet3D.java | 26 ++++----- .../facets/base/BaseObjectFacet2D.java | 3 +- .../facets/base/BaseObjectFacet3D.java | 24 ++++---- .../facets/base/BaseSparseFacet2D.java | 13 +++-- .../base/BaseStrictlySparseFieldFacet2D.java | 25 ++++---- .../facets/base/BooleanFieldFacet3D.java | 11 ++-- .../generation/facets/base/FieldFacet3D.java | 11 ++-- .../generation/facets/base/ObjectFacet3D.java | 10 ++-- .../base/SparseBooleanFieldFacet3D.java | 39 +++++++------ .../generation/facets/base/SparseFacet3D.java | 30 +++++----- .../facets/base/SparseFieldFacet3D.java | 41 ++++++------- .../facets/base/SparseObjectFacet3D.java | 31 +++++----- .../base/VerticallySparseBooleanFacet3D.java | 25 ++++---- .../AbstractWorldProviderDecorator.java | 3 +- .../world/internal/WorldProviderCore.java | 3 +- .../world/internal/WorldProviderCoreImpl.java | 5 +- .../world/internal/WorldProviderWrapper.java | 3 +- 56 files changed, 337 insertions(+), 319 deletions(-) diff --git a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java index 56f2e27cbe2..4a973f027ef 100644 --- a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java +++ b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java @@ -25,6 +25,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; @@ -180,7 +181,7 @@ public void dispose() { } @Override - public Collection getRelevantRegions() { + public Collection getRelevantRegions() { return Collections.emptySet(); } } diff --git a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java index 6877cbbcdaa..bb6111b54ce 100644 --- a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java +++ b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java @@ -24,6 +24,7 @@ import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.internal.ChunkViewCore; import org.terasology.world.internal.WorldInfo; import org.terasology.world.internal.WorldProviderCore; @@ -179,7 +180,7 @@ public WorldTime getTime() { } @Override - public Collection getRelevantRegions() { + public Collection getRelevantRegions() { return Collections.emptySet(); } diff --git a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java index a347eaa5784..97cac9a6d8f 100644 --- a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java @@ -19,9 +19,8 @@ import com.google.common.collect.ListMultimap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.FacetProvider; import org.terasology.world.generation.Region; @@ -77,7 +76,7 @@ public void setup() { Map, Border3D> borders = new HashMap<>(); borders.put(ElevationFacet.class, new Border3D(0, 0, 0)); - region = new RegionImpl(Region3i.createFromCenterExtents(new Vector3i(0, 0, 0), 4), + region = new RegionImpl(new BlockRegion(0, 0, 0).expand(4, 4, 4), facetProviderChains, borders); } diff --git a/engine-tests/src/test/java/org/terasology/world/generation/WorldBuilderTest.java b/engine-tests/src/test/java/org/terasology/world/generation/WorldBuilderTest.java index bddd28ba34e..6d3679f3026 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/WorldBuilderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/WorldBuilderTest.java @@ -18,8 +18,7 @@ import org.junit.jupiter.api.Test; import org.terasology.context.Context; import org.terasology.context.internal.ContextImpl; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.facets.base.BaseFacet3D; import org.terasology.world.generator.plugin.WorldGeneratorPluginLibrary; @@ -39,14 +38,14 @@ public void testBorderCalculation() { worldBuilder.addProvider(new Facet2Provider()); World world = worldBuilder.build(); - Region3i regionToGenerate = Region3i.createFromCenterExtents(new Vector3i(), 1); + BlockRegion regionToGenerate = new BlockRegion(0,0,0).expand(1, 1, 1); Region regionData = world.getWorldData(regionToGenerate); Facet1 facet1 = regionData.getFacet(Facet1.class); assertEquals(regionToGenerate, facet1.getWorldRegion()); Facet2 facet2 = regionData.getFacet(Facet2.class); - assertEquals(Region3i.createFromMinAndSize(new Vector3i(-3, -1, -3), new Vector3i(7, 3, 7)), facet2.getWorldRegion()); + assertEquals(new BlockRegion(-3, -1, -3).setSize(7, 3, 7), facet2.getWorldRegion()); } @Test @@ -58,17 +57,17 @@ public void testCumulativeBorderCalculation() { worldBuilder.addProvider(new Facet3Provider()); World world = worldBuilder.build(); - Region3i regionToGenerate = Region3i.createFromCenterExtents(new Vector3i(), 1); + BlockRegion regionToGenerate = new BlockRegion(0,0,0).expand(1, 1, 1); Region regionData = world.getWorldData(regionToGenerate); Facet3 facet3 = regionData.getFacet(Facet3.class); assertEquals(regionToGenerate, facet3.getWorldRegion()); Facet1 facet1 = regionData.getFacet(Facet1.class); - assertEquals(Region3i.createFromMinAndSize(new Vector3i(-2, -1, -2), new Vector3i(5, 3, 5)), facet1.getWorldRegion()); + assertEquals(new BlockRegion(-2, -1, -2).setSize(5, 3, 5), facet1.getWorldRegion()); Facet2 facet2 = regionData.getFacet(Facet2.class); - assertEquals(Region3i.createFromMinAndSize(new Vector3i(-4, -1, -4), new Vector3i(9, 3, 9)), facet2.getWorldRegion()); + assertEquals(new BlockRegion(-4, -1, -4).setSize(9, 3, 9), facet2.getWorldRegion()); } @Test @@ -80,7 +79,7 @@ public void testMultiplePathsBorderCalculation() { worldBuilder.addProvider(new Facet4Provider()); World world = worldBuilder.build(); - Region3i regionToGenerate = Region3i.createFromCenterExtents(new Vector3i(), 1); + BlockRegion regionToGenerate = new BlockRegion(0,0,0).expand(1, 1, 1); Region regionData = world.getWorldData(regionToGenerate); Facet1 facet1 = regionData.getFacet(Facet1.class); @@ -90,7 +89,7 @@ public void testMultiplePathsBorderCalculation() { assertEquals(regionToGenerate, facet4.getWorldRegion()); Facet2 facet2 = regionData.getFacet(Facet2.class); - assertEquals(Region3i.createFromMinAndSize(new Vector3i(-4, -1, -4), new Vector3i(9, 3, 9)), facet2.getWorldRegion()); + assertEquals(new BlockRegion(-4, -1, -4).setSize(9, 3, 9), facet2.getWorldRegion()); } @@ -104,7 +103,7 @@ public void testUpdating() { worldBuilder.addProvider(new Facet4Provider()); worldBuilder.addProvider(new FacetUpdater()); - Region3i regionToGenerate = Region3i.createFromCenterExtents(new Vector3i(), 1); + BlockRegion regionToGenerate = new BlockRegion(0,0,0).expand(1, 1, 1); World world; Region regionData; @@ -125,19 +124,19 @@ public void testUpdating() { public static class Facet1 extends BaseFacet3D { public boolean updated; - public Facet1(Region3i targetRegion, Border3D border) { + public Facet1(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } public static class Facet2 extends BaseFacet3D { - public Facet2(Region3i targetRegion, Border3D border) { + public Facet2(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } public static class Facet3 extends BaseFacet3D { - public Facet3(Region3i targetRegion, Border3D border) { + public Facet3(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } @@ -145,7 +144,7 @@ public Facet3(Region3i targetRegion, Border3D border) { public static class Facet4 extends BaseFacet3D { public boolean updated; - public Facet4(Region3i targetRegion, Border3D border) { + public Facet4(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java index fdb0a10f39a..4f06517a070 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java @@ -17,6 +17,7 @@ package org.terasology.world.generation.facets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseBooleanFieldFacet3D; import org.terasology.world.generation.facets.base.BooleanFieldFacet3D; @@ -27,7 +28,7 @@ public class BaseBooleanFacetTest extends BooleanFacetTest { @Override - protected BooleanFieldFacet3D createFacet(Region3i region, Border3D border) { + protected BooleanFieldFacet3D createFacet(BlockRegion region, Border3D border) { return new BaseBooleanFieldFacet3D(region, border) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseFieldFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseFieldFacetTest.java index a77e45a7c53..277c897aa80 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseFieldFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseFieldFacetTest.java @@ -16,7 +16,7 @@ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet3D; import org.terasology.world.generation.facets.base.FieldFacet3D; @@ -27,7 +27,7 @@ public class BaseFieldFacetTest extends FieldFacetTest { @Override - protected FieldFacet3D createFacet(Region3i region, Border3D border) { + protected FieldFacet3D createFacet(BlockRegion region, Border3D border) { return new BaseFieldFacet3D(region, border) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java index 654dc296c2a..7c903fcf13d 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java @@ -17,6 +17,7 @@ package org.terasology.world.generation.facets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseObjectFacet3D; import org.terasology.world.generation.facets.base.ObjectFacet3D; @@ -27,7 +28,7 @@ public class BaseObjectFacetTest extends ObjectFacetTest { @Override - protected ObjectFacet3D createFacet(Region3i region, Border3D border) { + protected ObjectFacet3D createFacet(BlockRegion region, Border3D border) { return new BaseObjectFacet3D(region, border, Integer.class) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BooleanFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BooleanFacetTest.java index 739b0c96cbe..43e762f026c 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BooleanFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BooleanFacetTest.java @@ -16,11 +16,11 @@ package org.terasology.world.generation.facets; +import org.joml.Vector3i; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BooleanFieldFacet3D; @@ -40,12 +40,12 @@ public void setup() { Border3D border = new Border3D(0, 0, 0).extendBy(0, 15, 10); Vector3i min = new Vector3i(10, 20, 30); Vector3i size = new Vector3i(40, 50, 60); - Region3i region = Region3i.createFromMinAndSize(min, size); + BlockRegion region = new BlockRegion(min).setSize(size); facet = createFacet(region, border); // facet = [worldMin=(0, 5, 20), relativeMin=(-10, -15, -10), size=(60, 65, 80)] } - protected abstract BooleanFieldFacet3D createFacet(Region3i region, Border3D extendBy); + protected abstract BooleanFieldFacet3D createFacet(BlockRegion region, Border3D extendBy); /** * Check unset values diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/FieldFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/FieldFacetTest.java index 74f52b13af6..2f290721a24 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/FieldFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/FieldFacetTest.java @@ -16,11 +16,11 @@ package org.terasology.world.generation.facets; +import org.joml.Vector3i; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.FieldFacet3D; @@ -39,12 +39,12 @@ public void setup() { Border3D border = new Border3D(0, 0, 0).extendBy(0, 15, 10); Vector3i min = new Vector3i(10, 20, 30); Vector3i size = new Vector3i(40, 50, 60); - Region3i region = Region3i.createFromMinAndSize(min, size); + BlockRegion region = new BlockRegion(min).setSize(size); facet = createFacet(region, border); // facet = [worldMin=(0, 5, 20), relativeMin=(-10, -15, -10), size=(60, 65, 80)] } - protected abstract FieldFacet3D createFacet(Region3i region, Border3D extendBy); + protected abstract FieldFacet3D createFacet(BlockRegion region, Border3D extendBy); /** * Check unset values diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/ObjectFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/ObjectFacetTest.java index aa86f96cafb..e50e60d878c 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/ObjectFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/ObjectFacetTest.java @@ -16,11 +16,11 @@ package org.terasology.world.generation.facets; +import org.joml.Vector3i; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.ObjectFacet3D; @@ -39,12 +39,12 @@ public void setup() { Border3D border = new Border3D(0, 0, 0).extendBy(0, 15, 10); Vector3i min = new Vector3i(10, 20, 30); Vector3i size = new Vector3i(40, 50, 60); - Region3i region = Region3i.createFromMinAndSize(min, size); + BlockRegion region = new BlockRegion(min).setSize(size); facet = createFacet(region, border); // facet = [worldMin=(0, 5, 20), relativeMin=(-10, -15, -10), size=(60, 65, 80)] } - protected abstract ObjectFacet3D createFacet(Region3i region, Border3D extendBy); + protected abstract ObjectFacet3D createFacet(BlockRegion region, Border3D extendBy); /** * Check unset values diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseBooleanFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseBooleanFacetTest.java index 3ea28e7b6b1..8263f91dcab 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseBooleanFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseBooleanFacetTest.java @@ -17,9 +17,9 @@ package org.terasology.world.generation.facets; import com.google.common.collect.ImmutableMap; +import org.joml.Vector3i; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BooleanFieldFacet3D; import org.terasology.world.generation.facets.base.SparseBooleanFieldFacet3D; @@ -37,7 +37,7 @@ public class SparseBooleanFacetTest extends BooleanFacetTest { private SparseBooleanFieldFacet3D facet; @Override - protected BooleanFieldFacet3D createFacet(Region3i region, Border3D border) { + protected BooleanFieldFacet3D createFacet(BlockRegion region, Border3D border) { facet = new SparseBooleanFieldFacet3D(region, border) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseFieldFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseFieldFacetTest.java index 56b27685ca1..16838578b4a 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseFieldFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseFieldFacetTest.java @@ -17,9 +17,9 @@ package org.terasology.world.generation.facets; import com.google.common.collect.ImmutableMap; +import org.joml.Vector3i; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.FieldFacet3D; import org.terasology.world.generation.facets.base.SparseFieldFacet3D; @@ -37,7 +37,7 @@ public class SparseFieldFacetTest extends FieldFacetTest { private SparseFieldFacet3D facet; @Override - protected FieldFacet3D createFacet(Region3i region, Border3D border) { + protected FieldFacet3D createFacet(BlockRegion region, Border3D border) { facet = new SparseFieldFacet3D(region, border) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseObjectFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseObjectFacetTest.java index 6b68f416eac..45722f99a47 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseObjectFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/SparseObjectFacetTest.java @@ -17,9 +17,9 @@ package org.terasology.world.generation.facets; import com.google.common.collect.ImmutableMap; +import org.joml.Vector3i; import org.junit.jupiter.api.Test; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.ObjectFacet3D; import org.terasology.world.generation.facets.base.SparseObjectFacet3D; @@ -37,7 +37,7 @@ public class SparseObjectFacetTest extends ObjectFacetTest { private SparseObjectFacet3D facet; @Override - protected ObjectFacet3D createFacet(Region3i region, Border3D border) { + protected ObjectFacet3D createFacet(BlockRegion region, Border3D border) { facet = new SparseObjectFacet3D(region, border) { // this class is abstract, but we don't want specific implementations }; diff --git a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java index e2e288cdab7..628ffedd654 100644 --- a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java +++ b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java @@ -21,9 +21,9 @@ import org.joml.Vector3f; import org.joml.Vector3i; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.math.SpiralIterable; import org.terasology.math.TeraMath; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Region; import org.terasology.world.generation.World; import org.terasology.world.generation.facets.ElevationFacet; @@ -51,7 +51,7 @@ protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius Vector3i desiredPos = new Vector3i(pos.x(), getStartHeight(world, pos), pos.y()); // try and find somewhere in this region a spot to land - Region3i spawnArea = Region3i.createFromCenterExtents(JomlUtil.from(desiredPos), JomlUtil.from(ext)); + BlockRegion spawnArea = new BlockRegion(desiredPos).expand(ext); Region worldRegion = world.getWorldData(spawnArea); Function> getWorld; @@ -115,7 +115,7 @@ protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius * Get the elevation at a single point, to use as the base point for searching. */ private int getStartHeight(World world, Vector2i pos) { - Region3i spawnArea = Region3i.createFromCenterExtents(JomlUtil.from(new Vector3i(pos.x(), 0, pos.y())), JomlUtil.from(new Vector3i())); + BlockRegion spawnArea = new BlockRegion(pos.x(), 0, pos.y()); Region worldRegion = world.getWorldData(spawnArea); ElevationFacet elevationFacet = worldRegion.getFacet(ElevationFacet.class); diff --git a/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/preview/FacetLayerPreview.java b/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/preview/FacetLayerPreview.java index 4d53cd4680b..11c89a3cad3 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/preview/FacetLayerPreview.java +++ b/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/preview/FacetLayerPreview.java @@ -17,15 +17,15 @@ package org.terasology.rendering.nui.layers.mainMenu.preview; import com.google.common.math.IntMath; +import org.joml.Vector3i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.math.Region3i; import org.terasology.math.geom.ImmutableVector2i; import org.terasology.math.geom.Rect2i; -import org.terasology.math.geom.Vector3i; import org.terasology.module.ModuleEnvironment; import org.terasology.rendering.assets.texture.TextureData; import org.terasology.rendering.nui.layers.mainMenu.ProgressListener; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.generation.Region; import org.terasology.world.generation.World; @@ -178,7 +178,7 @@ private Region createRegion(ImmutableVector2i chunkPos) { int minX = chunkPos.getX() * TILE_SIZE_X; int minZ = chunkPos.getY() * TILE_SIZE_Y; int height = vertChunks * ChunkConstants.SIZE_Y; - Region3i area3d = Region3i.createFromMinAndSize(new Vector3i(minX, 0, minZ), new Vector3i(TILE_SIZE_X, height, TILE_SIZE_Y)); + BlockRegion area3d = new BlockRegion(minX, 0, minZ).setSize(TILE_SIZE_X, height, TILE_SIZE_Y); World world = worldGenerator.getWorld(); Region region = world.getWorldData(area3d); return region; @@ -200,10 +200,8 @@ private static Rect2i worldToTileArea(Rect2i area) { * @return an image of that region */ private BufferedImage rasterize(Region region) { - - Vector3i extent = region.getRegion().size(); - int width = extent.x; - int height = extent.z; + int width = region.getRegion().getSizeX(); + int height = region.getRegion().getSizeZ(); WritableRaster raster = colorModel.createCompatibleWritableRaster(width, height); BufferedImage image = new BufferedImage(colorModel, raster, false, null); diff --git a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java index 679b2f67b67..58d90ef676e 100644 --- a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java +++ b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java @@ -16,14 +16,13 @@ package org.terasology.utilities.procedural; import com.google.common.math.IntMath; - -import org.terasology.math.geom.Rect2i; -import org.terasology.math.Region3i; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector2i; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.geom.Rect2i; +import org.terasology.world.block.BlockRegion; /** */ @@ -78,7 +77,7 @@ private float[] getSubset(float[] fullData, Rect2i fullRegion, Rect2i subRegion) float[] result = new float[subRegion.sizeX() * subRegion.sizeY()]; Vector2i offset = new Vector2i(subRegion.minX() - fullRegion.minX(), subRegion.minY() - fullRegion.minY()); for (int y = 0; y < subRegion.sizeY(); ++y) { - System.arraycopy(fullData, offset.getX() + fullRegion.sizeX() * (y + offset.getY()), result, subRegion.sizeX() * y, subRegion.sizeX()); + System.arraycopy(fullData, offset.x() + fullRegion.sizeX() * (y + offset.y()), result, subRegion.sizeX() * y, subRegion.sizeX()); } return result; } else { @@ -155,21 +154,21 @@ public float noise(float x, float y, float z) { return TeraMath.triLerp(q000, q100, q010, q110, q001, q101, q011, q111, xMod / sampleRate, yMod / sampleRate, zMod / sampleRate); } - public float[] noise(Region3i region) { - Region3i fullRegion = determineRequiredRegion(region); + public float[] noise(BlockRegion region) { + BlockRegion fullRegion = determineRequiredRegion(region); float[] keyData = getKeyValues(fullRegion); float[] fullData = mapExpand(keyData, fullRegion); return getSubset(fullData, fullRegion, region); } - private float[] getSubset(float[] fullData, Region3i fullRegion, Region3i subRegion) { - if (subRegion.sizeX() != fullRegion.sizeX() || subRegion.sizeY() != fullRegion.sizeY() || subRegion.sizeZ() != fullRegion.sizeZ()) { - float[] result = new float[subRegion.sizeX() * subRegion.sizeY() * subRegion.sizeZ()]; + private float[] getSubset(float[] fullData, BlockRegion fullRegion, BlockRegion subRegion) { + if (subRegion.getSizeX() != fullRegion.getSizeX() || subRegion.getSizeY() != fullRegion.getSizeY() || subRegion.getSizeZ() != fullRegion.getSizeZ()) { + float[] result = new float[subRegion.getSizeX() * subRegion.getSizeY() * subRegion.getSizeZ()]; Vector3i offset = new Vector3i(subRegion.minX() - fullRegion.minX(), subRegion.minY() - fullRegion.minY(), subRegion.minZ() - fullRegion.minZ()); - for (int z = 0; z < subRegion.sizeZ(); ++z) { - for (int y = 0; y < subRegion.sizeY(); ++y) { - System.arraycopy(fullData, offset.x + fullRegion.sizeX() * (y + offset.y + fullRegion.sizeY() * (z + offset.z)), - result, subRegion.sizeX() * (y + subRegion.sizeY() * z), subRegion.sizeX()); + for (int z = 0; z < subRegion.getSizeZ(); ++z) { + for (int y = 0; y < subRegion.getSizeY(); ++y) { + System.arraycopy(fullData, offset.x + fullRegion.getSizeX() * (y + offset.y + fullRegion.getSizeY() * (z + offset.z)), + result, subRegion.getSizeX() * (y + subRegion.getSizeY() * z), subRegion.getSizeX()); } } return result; @@ -178,11 +177,11 @@ private float[] getSubset(float[] fullData, Region3i fullRegion, Region3i subReg } } - private float[] mapExpand(float[] keyData, Region3i fullRegion) { - float[] fullData = new float[fullRegion.sizeX() * fullRegion.sizeY() * fullRegion.sizeZ()]; - int samplesX = fullRegion.sizeX() / sampleRate + 1; - int samplesY = fullRegion.sizeY() / sampleRate + 1; - int samplesZ = fullRegion.sizeZ() / sampleRate + 1; + private float[] mapExpand(float[] keyData, BlockRegion fullRegion) { + float[] fullData = new float[fullRegion.volume()]; + int samplesX = fullRegion.getSizeX() / sampleRate + 1; + int samplesY = fullRegion.getSizeY() / sampleRate + 1; + int samplesZ = fullRegion.getSizeZ() / sampleRate + 1; for (int z = 0; z < samplesZ - 1; z++) { for (int y = 0; y < samplesY - 1; y++) { for (int x = 0; x < samplesX - 1; x++) { @@ -197,7 +196,7 @@ private float[] mapExpand(float[] keyData, Region3i fullRegion) { for (int innerZ = 0; innerZ < sampleRate; ++innerZ) { for (int innerY = 0; innerY < sampleRate; ++innerY) { for (int innerX = 0; innerX < sampleRate; ++innerX) { - fullData[x * sampleRate + innerX + fullRegion.sizeX() * (y * sampleRate + innerY + fullRegion.sizeY() * (z * sampleRate + innerZ))] = + fullData[x * sampleRate + innerX + fullRegion.getSizeX() * (y * sampleRate + innerY + fullRegion.getSizeY() * (z * sampleRate + innerZ))] = TeraMath.triLerp(q000, q100, q010, q110, q001, q101, q011, q111, (float) innerX / sampleRate, (float) innerY / sampleRate, (float) innerZ / sampleRate); } @@ -209,10 +208,10 @@ private float[] mapExpand(float[] keyData, Region3i fullRegion) { return fullData; } - private float[] getKeyValues(Region3i fullRegion) { - int xDim = fullRegion.sizeX() / sampleRate + 1; - int yDim = fullRegion.sizeY() / sampleRate + 1; - int zDim = fullRegion.sizeZ() / sampleRate + 1; + private float[] getKeyValues(BlockRegion fullRegion) { + int xDim = fullRegion.getSizeX() / sampleRate + 1; + int yDim = fullRegion.getSizeY() / sampleRate + 1; + int zDim = fullRegion.getSizeZ() / sampleRate + 1; float[] fullData = new float[xDim * yDim * zDim]; for (int z = 0; z < zDim; z++) { for (int y = 0; y < yDim; y++) { @@ -227,13 +226,13 @@ private float[] getKeyValues(Region3i fullRegion) { return fullData; } - private Region3i determineRequiredRegion(Region3i region) { + private BlockRegion determineRequiredRegion(BlockRegion region) { int newMinX = region.minX() - IntMath.mod(region.minX(), sampleRate); int newMinY = region.minY() - IntMath.mod(region.minY(), sampleRate); int newMinZ = region.minZ() - IntMath.mod(region.minZ(), sampleRate); int newMaxX = region.maxX() + 4 - IntMath.mod(region.maxX(), sampleRate) - 1; int newMaxY = region.maxY() + 4 - IntMath.mod(region.maxY(), sampleRate) - 1; int newMaxZ = region.maxZ() + 4 - IntMath.mod(region.maxZ(), sampleRate) - 1; - return Region3i.createFromMinMax(new Vector3i(newMinX, newMinY, newMinZ), new Vector3i(newMaxX, newMaxY, newMaxZ)); + return new BlockRegion(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java index 79939ac6e3a..9bdd8213549 100644 --- a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java @@ -24,6 +24,7 @@ import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; /** * This interface describes the core of a chunk: @@ -316,7 +317,7 @@ public interface CoreChunk { /** * @return Chunk's Region */ - Region3i getRegion(); + BlockRegion getRegion(); int getEstimatedMemoryConsumptionInBytes(); diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java index a4ac193ed9e..8cb59a45f20 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java @@ -21,7 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.math.AABB; -import org.terasology.math.Region3i; import org.terasology.math.geom.BaseVector3i; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; @@ -30,6 +29,7 @@ import org.terasology.rendering.primitives.ChunkMesh; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkBlockIterator; import org.terasology.world.chunks.ChunkConstants; @@ -43,12 +43,11 @@ import java.text.DecimalFormat; /** - * Chunks are the basic components of the world. Each chunk contains a fixed amount of blocks - * determined by its dimensions. They are used to manage the world efficiently and - * to reduce the batch count within the render loop. + * Chunks are the basic components of the world. Each chunk contains a fixed amount of blocks determined by its + * dimensions. They are used to manage the world efficiently and to reduce the batch count within the render loop. *

- * Chunks are tessellated on creation and saved to vertex arrays. From those VBOs are generated - * which are then used for the actual rendering process. + * Chunks are tessellated on creation and saved to vertex arrays. From those VBOs are generated which are then used for + * the actual rendering process. */ public class ChunkImpl implements Chunk { @@ -71,7 +70,7 @@ public class ChunkImpl implements Chunk { private volatile TeraArray[] extraDataSnapshots; private AABB aabb; - private Region3i region; + private BlockRegion region; private boolean disposed; private boolean ready; @@ -102,8 +101,11 @@ public ChunkImpl(Vector3i chunkPos, TeraArray blocks, TeraArray[] extra, BlockMa lightData = new TeraDenseArray8Bit(getChunkSizeX(), getChunkSizeY(), getChunkSizeZ()); dirty = true; this.blockManager = blockManager; - region = Region3i.createFromMinAndSize(new Vector3i(chunkPos.x * ChunkConstants.SIZE_X, chunkPos.y * ChunkConstants.SIZE_Y, chunkPos.z * ChunkConstants.SIZE_Z), - ChunkConstants.CHUNK_SIZE); + region = new BlockRegion( + chunkPos.x * ChunkConstants.SIZE_X, + chunkPos.y * ChunkConstants.SIZE_Y, + chunkPos.z * ChunkConstants.SIZE_Z) + .setSize(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); ChunkMonitor.fireChunkCreated(this); } @@ -114,7 +116,7 @@ public Vector3i getPosition() { @Override public org.joml.Vector3i getPosition(org.joml.Vector3i dest) { - return dest.set(chunkPos.x,chunkPos.y,chunkPos.z); + return dest.set(chunkPos.x, chunkPos.y, chunkPos.z); } @Override @@ -177,7 +179,7 @@ public Block setBlock(BaseVector3i pos, Block block) { @Override public Block setBlock(Vector3ic pos, Block block) { - return setBlock(pos.x(),pos.y(),pos.z(),block); + return setBlock(pos.x(), pos.y(), pos.z(), block); } @Override @@ -517,7 +519,8 @@ public void prepareForReactivation() { if (disposed) { disposed = false; sunlightData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); - sunlightRegenData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); + sunlightRegenData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, + ChunkConstants.SIZE_Z); lightData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); } } @@ -552,7 +555,7 @@ public boolean isDisposed() { } @Override - public Region3i getRegion() { + public BlockRegion getRegion() { return region; } @@ -582,8 +585,8 @@ public EntityData.ChunkStore.Builder encode() { } /** - * Calling this method results in a (cheap) snapshot to be taken of the current state of the chunk. - * This snapshot can then be obtained and rleased by calling {@link #encodeAndReleaseSnapshot()}. + * Calling this method results in a (cheap) snapshot to be taken of the current state of the chunk. This snapshot + * can then be obtained and rleased by calling {@link #encodeAndReleaseSnapshot()}. */ public void createSnapshot() { this.blockDataSnapshot = this.blockData; @@ -592,10 +595,9 @@ public void createSnapshot() { } /** - * This method can only be - * called once after {@link #createSnapshot()} has been called. It can be called from a different thread than - * {@link #createSnapshot()}, but it must be made sure that neither method is still running when the other gets - * called. + * This method can only be called once after {@link #createSnapshot()} has been called. It can be called from a + * different thread than {@link #createSnapshot()}, but it must be made sure that neither method is still running + * when the other gets called. * * @return an encoded version of the snapshot taken with {@link #createSnapshot()}. */ diff --git a/engine/src/main/java/org/terasology/world/generation/Border3D.java b/engine/src/main/java/org/terasology/world/generation/Border3D.java index 3706ac3ea7c..38c3d6edae8 100644 --- a/engine/src/main/java/org/terasology/world/generation/Border3D.java +++ b/engine/src/main/java/org/terasology/world/generation/Border3D.java @@ -16,9 +16,9 @@ package org.terasology.world.generation; import com.google.common.base.Preconditions; +import org.joml.Vector3i; import org.terasology.math.geom.Rect2i; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import java.util.Objects; @@ -65,16 +65,17 @@ public int getSides() { * @param region The original region to be used. * @return The 2D representation with the additional space added to it. */ - public Rect2i expandTo2D(Region3i region) { + public Rect2i expandTo2D(BlockRegion region) { return Rect2i.createFromMinAndMax(region.minX() - getSides(), region.minZ() - getSides(), region.maxX() + getSides(), region.maxZ() + getSides()); } /** - * Same as {@code {@link #expandTo2D(Region3i)}} but with a Vector3i instead of a Region3i. + * Same as {@code {@link #expandTo2D(BlockRegion)}} but with a Vector3i instead of a Region3i. * @param size The size used. * @return The 2D representation with the additional space added to it with the additional space added to it in the 3 dimensions. */ + //TODO: offer a variant that takes three integers to potentially avoid allocation of superfluous vectors public Rect2i expandTo2D(Vector3i size) { return Rect2i.createFromMinAndMax(-getSides(), -getSides(), size.x + getSides() - 1, size.z + getSides() - 1); } @@ -84,19 +85,20 @@ public Rect2i expandTo2D(Vector3i size) { * @param region The region to be expanded with the borders. * @return The 3D world representation with the additional space added to it in the 3 dimensions. */ - public Region3i expandTo3D(Region3i region) { - return Region3i.createFromMinMax(new Vector3i(region.minX() - sides, region.minY() - bottom, region.minZ() - sides), - new Vector3i(region.maxX() + sides, region.maxY() + top, region.maxZ() + sides)); + public BlockRegion expandTo3D(BlockRegion region) { + return new BlockRegion(region.minX() - sides, region.minY() - bottom, region.minZ() - sides, + region.maxX() + sides, region.maxY() + top, region.maxZ() + sides); } /** - * Same as {@code {@link #expandTo3D(Region3i)}}} but with a Vector3i instead of a Region3i. + * Same as {@code {@link #expandTo3D(BlockRegion)}}} but with a Vector3i instead of a Region3i. * @param size The size to be used. * @return The 3D world representation with the additional space added to it in the 3 dimensions. */ - public Region3i expandTo3D(Vector3i size) { - return Region3i.createFromMinMax(new Vector3i(-sides, -bottom, -sides), - new Vector3i(size.x + sides - 1, size.y + top - 1, size.z + sides - 1)); + //TODO: offer a variant that takes three integers to potentially avoid allocation of superfluous vectors + public BlockRegion expandTo3D(Vector3i size) { + return new BlockRegion(-sides, -bottom, -sides, + size.x + sides - 1, size.y + top - 1, size.z + sides - 1); } /** diff --git a/engine/src/main/java/org/terasology/world/generation/GeneratingRegion.java b/engine/src/main/java/org/terasology/world/generation/GeneratingRegion.java index 890bc37da44..cfb4d4bb729 100644 --- a/engine/src/main/java/org/terasology/world/generation/GeneratingRegion.java +++ b/engine/src/main/java/org/terasology/world/generation/GeneratingRegion.java @@ -15,13 +15,13 @@ */ package org.terasology.world.generation; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; /** */ public interface GeneratingRegion { - Region3i getRegion(); + BlockRegion getRegion(); T getRegionFacet(Class type); diff --git a/engine/src/main/java/org/terasology/world/generation/Region.java b/engine/src/main/java/org/terasology/world/generation/Region.java index 027cb19916c..508dee19c6a 100644 --- a/engine/src/main/java/org/terasology/world/generation/Region.java +++ b/engine/src/main/java/org/terasology/world/generation/Region.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; /** */ @@ -23,5 +23,5 @@ public interface Region { T getFacet(Class dataType); - Region3i getRegion(); + BlockRegion getRegion(); } diff --git a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java index 5b8b4d31b86..5d0c275ba7d 100644 --- a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java @@ -19,6 +19,7 @@ import com.google.common.collect.Sets; import org.terasology.math.Region3i; import org.terasology.utilities.collection.TypeMap; +import org.terasology.world.block.BlockRegion; import java.util.Map; import java.util.Set; @@ -27,7 +28,7 @@ */ public class RegionImpl implements Region, GeneratingRegion { - private final Region3i region; + private final BlockRegion region; private final ListMultimap, FacetProvider> facetProviderChains; private final Map, Border3D> borders; @@ -35,7 +36,7 @@ public class RegionImpl implements Region, GeneratingRegion { private final Set processedProviders = Sets.newHashSet(); private final TypeMap generatedFacets = TypeMap.create(); - public RegionImpl(Region3i region, ListMultimap, FacetProvider> facetProviderChains, Map, Border3D> borders) { + public RegionImpl(BlockRegion region, ListMultimap, FacetProvider> facetProviderChains, Map, Border3D> borders) { this.region = region; this.facetProviderChains = facetProviderChains; this.borders = borders; @@ -56,7 +57,7 @@ public T getFacet(Class dataType) { } @Override - public Region3i getRegion() { + public BlockRegion getRegion() { return region; } diff --git a/engine/src/main/java/org/terasology/world/generation/World.java b/engine/src/main/java/org/terasology/world/generation/World.java index 7a0f976346b..42756f8070b 100644 --- a/engine/src/main/java/org/terasology/world/generation/World.java +++ b/engine/src/main/java/org/terasology/world/generation/World.java @@ -16,6 +16,7 @@ package org.terasology.world.generation; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.CoreChunk; import java.util.Set; @@ -24,7 +25,7 @@ */ public interface World { - Region getWorldData(Region3i region); + Region getWorldData(BlockRegion region); /** * @return the sea level, measured in blocks. May be used for setting diff --git a/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java index cd9083db19c..503f2e24f92 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java @@ -16,6 +16,7 @@ package org.terasology.world.generation; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; /** */ @@ -24,10 +25,10 @@ public interface WorldFacet3D extends WorldFacet { /** * @return The region of the world covered by this facet */ - Region3i getWorldRegion(); + BlockRegion getWorldRegion(); /** * @return The region covered by this facet, relative to the target region */ - Region3i getRelativeRegion(); + BlockRegion getRelativeRegion(); } diff --git a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java index c49cc2e1577..ebdbfb52215 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java @@ -18,6 +18,7 @@ import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.CoreChunk; import java.util.Collection; @@ -48,7 +49,7 @@ public WorldImpl(ListMultimap, FacetProvider> facetP } @Override - public Region getWorldData(Region3i region) { + public Region getWorldData(BlockRegion region) { return new RegionImpl(region, facetProviderChains, borders); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java index 1cae3269a63..1cebea62245 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java @@ -16,6 +16,7 @@ package org.terasology.world.generation.facets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet3D; @@ -23,7 +24,7 @@ */ public class DensityFacet extends BaseFieldFacet3D { - public DensityFacet(Region3i targetRegion, Border3D border) { + public DensityFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java index 45d082ef787..62fca43a7c8 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java @@ -4,6 +4,7 @@ package org.terasology.world.generation.facets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; @@ -16,7 +17,7 @@ */ public class ElevationFacet extends BaseFieldFacet2D { - public ElevationFacet(Region3i targetRegion, Border3D border) { + public ElevationFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SeaLevelFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SeaLevelFacet.java index c3d81ffb372..0924c9f91b9 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SeaLevelFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SeaLevelFacet.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFacet2D; @@ -26,7 +26,7 @@ public class SeaLevelFacet extends BaseFacet2D { int seaLevel; - public SeaLevelFacet(Region3i targetRegion, Border3D border) { + public SeaLevelFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SpawnHeightFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SpawnHeightFacet.java index 346b194c532..0e883ee52c0 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SpawnHeightFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SpawnHeightFacet.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseStrictlySparseFieldFacet2D; @@ -23,7 +23,7 @@ * Stores the height at which the player may be spawned, if it exists for a given coordinate */ public class SpawnHeightFacet extends BaseStrictlySparseFieldFacet2D { - public SpawnHeightFacet(Region3i targetRegion, Border3D border) { + public SpawnHeightFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/StrictlySparseSeaLevelFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/StrictlySparseSeaLevelFacet.java index 7c67d014ce4..7543d5758c9 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/StrictlySparseSeaLevelFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/StrictlySparseSeaLevelFacet.java @@ -15,8 +15,8 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; import org.terasology.math.TeraMath; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseStrictlySparseFieldFacet2D; @@ -26,7 +26,7 @@ * Stores the sea level, if it varies or is not defined for certain coordinates. */ public class StrictlySparseSeaLevelFacet extends BaseStrictlySparseFieldFacet2D { - public StrictlySparseSeaLevelFacet(Region3i targetRegion, Border3D border) { + public StrictlySparseSeaLevelFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java index f1c2938629a..11f71c6d0d2 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java @@ -16,6 +16,7 @@ package org.terasology.world.generation.facets; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; @@ -26,7 +27,7 @@ */ public class SurfaceDepthFacet extends BaseFieldFacet2D { - public SurfaceDepthFacet(Region3i targetRegion, Border3D border) { + public SurfaceDepthFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHumidityFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHumidityFacet.java index d6b0eb892a3..eca19e694f4 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHumidityFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceHumidityFacet.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.FacetName; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; @@ -27,7 +27,7 @@ public class SurfaceHumidityFacet extends BaseFieldFacet2D { static int maxSamplesPerRegion = 5; - public SurfaceHumidityFacet(Region3i targetRegion, Border3D border) { + public SurfaceHumidityFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceTemperatureFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceTemperatureFacet.java index e3844d6e4b4..bec3f6ce579 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceTemperatureFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceTemperatureFacet.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.FacetName; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; @@ -26,7 +26,7 @@ public class SurfaceTemperatureFacet extends BaseFieldFacet2D { static int maxSamplesPerRegion = 5; - public SurfaceTemperatureFacet(Region3i targetRegion, Border3D border) { + public SurfaceTemperatureFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java index 3d10a41ef26..6bec63abfcf 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfacesFacet.java @@ -4,7 +4,7 @@ package org.terasology.world.generation.facets; import org.joml.Vector3ic; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.VerticallySparseBooleanFacet3D; @@ -18,7 +18,7 @@ */ public class SurfacesFacet extends VerticallySparseBooleanFacet3D { - public SurfacesFacet(Region3i targetRegion, Border3D border) { + public SurfacesFacet(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java index 54d15def2c2..e1b557c64e2 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java @@ -16,9 +16,8 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; - -import org.terasology.math.Region3i; import org.terasology.math.geom.Vector2i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; /** @@ -30,7 +29,7 @@ public abstract class BaseBooleanFieldFacet2D extends BaseFacet2D implements Boo private final boolean[] data; - public BaseBooleanFieldFacet2D(Region3i targetRegion, Border3D border) { + public BaseBooleanFieldFacet2D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); Vector2i size = getRelativeRegion().size(); data = new boolean[size.x * size.y]; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java index d92e71904fc..e116c3cdd87 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java @@ -16,8 +16,9 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; /** @@ -26,9 +27,9 @@ public abstract class BaseBooleanFieldFacet3D extends BaseFacet3D implements Boo private boolean[] data; - public BaseBooleanFieldFacet3D(Region3i targetRegion, Border3D border) { + public BaseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); - Vector3i size = getRelativeRegion().size(); + Vector3i size = getRelativeRegion().getSize(new Vector3i()); data = new boolean[size.x * size.y * size.z]; } @@ -38,8 +39,8 @@ public boolean get(int x, int y, int z) { } @Override - public boolean get(Vector3i pos) { - return get(pos.x, pos.y, pos.z); + public boolean get(Vector3ic pos) { + return get(pos.x(), pos.y(), pos.z()); } @Override @@ -48,8 +49,8 @@ public boolean getWorld(int x, int y, int z) { } @Override - public boolean getWorld(Vector3i pos) { - return getWorld(pos.x, pos.y, pos.z); + public boolean getWorld(Vector3ic pos) { + return getWorld(pos.x(), pos.y(), pos.z()); } public boolean[] getInternal() { @@ -62,8 +63,8 @@ public void set(int x, int y, int z, boolean value) { } @Override - public void set(Vector3i pos, boolean value) { - set(pos.x, pos.y, pos.z, value); + public void set(Vector3ic pos, boolean value) { + set(pos.x(), pos.y(), pos.z(), value); } @Override @@ -72,8 +73,8 @@ public void setWorld(int x, int y, int z, boolean value) { } @Override - public void setWorld(Vector3i pos, boolean value) { - setWorld(pos.x, pos.y, pos.z, value); + public void setWorld(Vector3ic pos, boolean value) { + setWorld(pos.x(), pos.y(), pos.z(), value); } public void set(boolean[] newData) { diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java index 474e783b25a..9c6c83a3276 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java @@ -15,8 +15,10 @@ */ package org.terasology.world.generation.facets.base; +import org.joml.Vector3i; import org.terasology.math.geom.Rect2i; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet2D; @@ -27,9 +29,9 @@ public class BaseFacet2D implements WorldFacet2D { private Rect2i worldRegion; private Rect2i relativeRegion; - public BaseFacet2D(Region3i targetRegion, Border3D border) { + public BaseFacet2D(BlockRegion targetRegion, Border3D border) { worldRegion = border.expandTo2D(targetRegion); - relativeRegion = border.expandTo2D(targetRegion.size()); + relativeRegion = border.expandTo2D(targetRegion.getSize(new Vector3i())); } @Override diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java index d824284d02b..7775d5a9d8c 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java @@ -15,7 +15,8 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.Region3i; +import org.joml.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; @@ -23,35 +24,35 @@ */ public class BaseFacet3D implements WorldFacet3D { - private Region3i worldRegion; - private Region3i relativeRegion; + private BlockRegion worldRegion; + private BlockRegion relativeRegion; - public BaseFacet3D(Region3i targetRegion, Border3D border) { + public BaseFacet3D(BlockRegion targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); - relativeRegion = border.expandTo3D(targetRegion.size()); + relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); } @Override - public final Region3i getWorldRegion() { + public final BlockRegion getWorldRegion() { return worldRegion; } @Override - public final Region3i getRelativeRegion() { + public final BlockRegion getRelativeRegion() { return relativeRegion; } protected final int getRelativeIndex(int x, int y, int z) { - if (!relativeRegion.encompasses(x, y, z)) { + if (!relativeRegion.contains(x, y, z)) { throw new IllegalArgumentException(String.format("Out of bounds: (%d, %d, %d) for region %s", x, y, z, relativeRegion.toString())); } - return x - relativeRegion.minX() + relativeRegion.sizeX() * (y - relativeRegion.minY() + relativeRegion.sizeY() * (z - relativeRegion.minZ())); + return x - relativeRegion.minX() + relativeRegion.getSizeX() * (y - relativeRegion.minY() + relativeRegion.getSizeY() * (z - relativeRegion.minZ())); } protected final int getWorldIndex(int x, int y, int z) { - if (!worldRegion.encompasses(x, y, z)) { + if (!worldRegion.contains(x, y, z)) { throw new IllegalArgumentException(String.format("Out of bounds: (%d, %d, %d) for region %s", x, y, z, worldRegion.toString())); } - return x - worldRegion.minX() + worldRegion.sizeX() * (y - worldRegion.minY() + worldRegion.sizeY() * (z - worldRegion.minZ())); + return x - worldRegion.minX() + worldRegion.getSizeX() * (y - worldRegion.minY() + worldRegion.getSizeY() * (z - worldRegion.minZ())); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java index e15c3fce956..d98a691012a 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java @@ -20,6 +20,7 @@ import org.terasology.math.Region3i; import org.terasology.math.geom.BaseVector2i; import org.terasology.math.geom.Vector2i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; /** @@ -28,7 +29,7 @@ public abstract class BaseFieldFacet2D extends BaseFacet2D implements FieldFacet private float[] data; - public BaseFieldFacet2D(Region3i targetRegion, Border3D border) { + public BaseFieldFacet2D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); Vector2i size = getRelativeRegion().size(); this.data = new float[size.x * size.y]; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java index 4331eddf709..476343434e7 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java @@ -16,8 +16,9 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; /** @@ -26,10 +27,9 @@ public abstract class BaseFieldFacet3D extends BaseFacet3D implements FieldFacet private float[] data; - public BaseFieldFacet3D(Region3i targetRegion, Border3D border) { + public BaseFieldFacet3D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); - Vector3i size = getRelativeRegion().size(); - this.data = new float[size.x * size.y * size.z]; + this.data = new float[getRelativeRegion().volume()]; } @Override @@ -38,8 +38,8 @@ public float get(int x, int y, int z) { } @Override - public float get(Vector3i pos) { - return get(pos.x, pos.y, pos.z); + public float get(Vector3ic pos) { + return get(pos.x(), pos.y(), pos.z()); } @Override @@ -48,8 +48,8 @@ public float getWorld(int x, int y, int z) { } @Override - public float getWorld(Vector3i pos) { - return getWorld(pos.x, pos.y, pos.z); + public float getWorld(Vector3ic pos) { + return getWorld(pos.x(), pos.y(), pos.z()); } public float[] getInternal() { @@ -62,8 +62,8 @@ public void set(int x, int y, int z, float value) { } @Override - public void set(Vector3i pos, float value) { - set(pos.x, pos.y, pos.z, value); + public void set(Vector3ic pos, float value) { + set(pos.x(), pos.y(), pos.z(), value); } @Override @@ -72,8 +72,8 @@ public void setWorld(int x, int y, int z, float value) { } @Override - public void setWorld(Vector3i pos, float value) { - setWorld(pos.x, pos.y, pos.z, value); + public void setWorld(Vector3ic pos, float value) { + setWorld(pos.x(), pos.y(), pos.z(), value); } public void set(float[] newData) { diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java index 398ef676829..b9a899fb9b3 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java @@ -20,6 +20,7 @@ import org.terasology.math.Region3i; import org.terasology.math.geom.BaseVector2i; import org.terasology.math.geom.Vector2i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import java.lang.reflect.Array; @@ -30,7 +31,7 @@ public abstract class BaseObjectFacet2D extends BaseFacet2D implements Object private T[] data; - public BaseObjectFacet2D(Region3i targetRegion, Border3D border, Class objectType) { + public BaseObjectFacet2D(BlockRegion targetRegion, Border3D border, Class objectType) { super(targetRegion, border); Vector2i size = getRelativeRegion().size(); this.data = (T[]) Array.newInstance(objectType, size.x * size.y); diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet3D.java index 83ffd852eec..35d2faec96e 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet3D.java @@ -15,14 +15,13 @@ */ package org.terasology.world.generation.facets.base; -import java.lang.reflect.Array; - -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector3i; -import org.terasology.math.geom.Vector3i; +import com.google.common.base.Preconditions; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; -import com.google.common.base.Preconditions; +import java.lang.reflect.Array; /** * Base class for storing objects of the specified type in a 3D grid for a facet. @@ -32,10 +31,9 @@ public abstract class BaseObjectFacet3D extends BaseFacet3D implements ObjectFacet3D { private T[] data; - public BaseObjectFacet3D(Region3i targetRegion, Border3D border, Class objectType) { + public BaseObjectFacet3D(BlockRegion targetRegion, Border3D border, Class objectType) { super(targetRegion, border); - Vector3i size = getRelativeRegion().size(); - this.data = (T[]) Array.newInstance(objectType, size.x * size.y * size.z); + this.data = (T[]) Array.newInstance(objectType, getRelativeRegion().volume()); } @Override @@ -44,7 +42,7 @@ public T get(int x, int y, int z) { } @Override - public T get(BaseVector3i pos) { + public T get(Vector3ic pos) { return get(pos.x(), pos.y(), pos.z()); } @@ -54,7 +52,7 @@ public T getWorld(int x, int y, int z) { } @Override - public T getWorld(BaseVector3i pos) { + public T getWorld(Vector3ic pos) { return getWorld(pos.x(), pos.y(), pos.z()); } @@ -68,7 +66,7 @@ public void set(int x, int y, int z, T value) { } @Override - public void set(BaseVector3i pos, T value) { + public void set(Vector3ic pos, T value) { set(pos.x(), pos.y(), pos.z(), value); } @@ -78,7 +76,7 @@ public void setWorld(int x, int y, int z, T value) { } @Override - public void setWorld(BaseVector3i pos, T value) { + public void setWorld(Vector3ic pos, T value) { setWorld(pos.x(), pos.y(), pos.z(), value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java index 5cd1deb8482..380196ff0b1 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java @@ -15,10 +15,11 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector2i; +import org.joml.Vector2i; +import org.joml.Vector2ic; +import org.joml.Vector3i; import org.terasology.math.geom.Rect2i; -import org.terasology.math.geom.Vector2i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet2D; @@ -29,9 +30,9 @@ public abstract class BaseSparseFacet2D implements WorldFacet2D { private Rect2i worldRegion; private Rect2i relativeRegion; - public BaseSparseFacet2D(Region3i targetRegion, Border3D border) { + public BaseSparseFacet2D(BlockRegion targetRegion, Border3D border) { worldRegion = border.expandTo2D(targetRegion); - relativeRegion = border.expandTo2D(targetRegion.size()); + relativeRegion = border.expandTo2D(targetRegion.getSize(new Vector3i())); } @Override @@ -44,7 +45,7 @@ public Rect2i getRelativeRegion() { return relativeRegion; } - protected BaseVector2i worldToRelative(int x, int y) { + protected Vector2ic worldToRelative(int x, int y) { return new Vector2i(x - getWorldRegion().minX() + getRelativeRegion().minX(), y - getWorldRegion().minY() + getRelativeRegion().minY()); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java index 010363ed0b7..1489c0dfae7 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java @@ -15,20 +15,21 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Vector2i; +import org.joml.Vector2i; +import org.joml.Vector2ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; -import java.util.*; +import java.util.HashMap; +import java.util.Optional; /*** * A strictly-sparse (not necessarily defined at all points) alternative to {@link BaseFieldFacet2D} */ public abstract class BaseStrictlySparseFieldFacet2D extends BaseSparseFacet2D { - private HashMap data = new HashMap<>(); + private HashMap data = new HashMap<>(); - public BaseStrictlySparseFieldFacet2D(Region3i targetRegion, Border3D border) { + public BaseStrictlySparseFieldFacet2D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } @@ -36,7 +37,7 @@ public Optional get(int x, int y) { return get(new Vector2i(x, y)); } - public Optional get(BaseVector2i pos) { + public Optional get(Vector2ic pos) { validateCoord(pos.x(), pos.y(), getRelativeRegion()); return Optional.ofNullable(data.getOrDefault(pos, null)); @@ -48,7 +49,7 @@ public Optional getWorld(int x, int y) { return Optional.ofNullable(data.getOrDefault(worldToRelative(x, y), null)); } - public Optional getWorld(BaseVector2i pos) { + public Optional getWorld(Vector2ic pos) { return getWorld(pos.x(), pos.y()); } @@ -56,7 +57,7 @@ public void set(int x, int y, float value) { set(new Vector2i(x, y), value); } - public void set(BaseVector2i pos, float value) { + public void set(Vector2ic pos, float value) { validateCoord(pos.x(), pos.y(), getRelativeRegion()); data.put(pos, value); @@ -68,7 +69,7 @@ public void setWorld(int x, int y, float value) { data.put(worldToRelative(x, y), value); } - public void setWorld(BaseVector2i pos, float value) { + public void setWorld(Vector2ic pos, float value) { setWorld(pos.x(), pos.y(), value); } @@ -76,7 +77,7 @@ public void unset(int x, int y) { unset(new Vector2i(x, y)); } - public void unset(BaseVector2i pos) { + public void unset(Vector2ic pos) { validateCoord(pos.x(), pos.y(), getRelativeRegion()); data.remove(pos); @@ -88,7 +89,7 @@ public void unsetWorld(int x, int y) { data.remove(worldToRelative(x, y)); } - public void unsetWorld(BaseVector2i pos) { + public void unsetWorld(Vector2ic pos) { unsetWorld(pos.x(), pos.y()); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet3D.java index 49b103e0850..2059ede26eb 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet3D.java @@ -15,7 +15,8 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.world.generation.WorldFacet3D; /** @@ -24,17 +25,17 @@ public interface BooleanFieldFacet3D extends WorldFacet3D { boolean get(int x, int y, int z); - boolean get(Vector3i pos); + boolean get(Vector3ic pos); boolean getWorld(int x, int y, int z); - boolean getWorld(Vector3i pos); + boolean getWorld(Vector3ic pos); void set(int x, int y, int z, boolean value); - void set(Vector3i pos, boolean value); + void set(Vector3ic pos, boolean value); void setWorld(int x, int y, int z, boolean value); - void setWorld(Vector3i pos, boolean value); + void setWorld(Vector3ic pos, boolean value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet3D.java index 2f156290249..9bad175b998 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet3D.java @@ -15,7 +15,8 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.world.generation.WorldFacet3D; /** @@ -24,17 +25,17 @@ public interface FieldFacet3D extends WorldFacet3D { float get(int x, int y, int z); - float get(Vector3i pos); + float get(Vector3ic pos); float getWorld(int x, int y, int z); - float getWorld(Vector3i pos); + float getWorld(Vector3ic pos); void set(int x, int y, int z, float value); - void set(Vector3i pos, float value); + void set(Vector3ic pos, float value); void setWorld(int x, int y, int z, float value); - void setWorld(Vector3i pos, float value); + void setWorld(Vector3ic pos, float value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet3D.java index ccca03af94e..693021e7c83 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet3D.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.BaseVector3i; +import org.joml.Vector3ic; import org.terasology.world.generation.WorldFacet3D; /** @@ -24,17 +24,17 @@ public interface ObjectFacet3D extends WorldFacet3D { T get(int x, int y, int z); - T get(BaseVector3i pos); + T get(Vector3ic pos); T getWorld(int x, int y, int z); - T getWorld(BaseVector3i pos); + T getWorld(Vector3ic pos); void set(int x, int y, int z, T value); - void set(BaseVector3i pos, T value); + void set(Vector3ic pos, T value); void setWorld(int x, int y, int z, T value); - void setWorld(BaseVector3i pos, T value); + void setWorld(Vector3ic pos, T value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java index 68a69241464..39a349c8593 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java @@ -17,8 +17,9 @@ package org.terasology.world.generation.facets.base; import com.google.common.collect.Maps; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -26,21 +27,19 @@ import java.util.Map.Entry; /** - * A sparse (map-based) implementation - * of {@link ObjectFacet3D}. - * + * A sparse (map-based) implementation of {@link ObjectFacet3D}. */ public abstract class SparseBooleanFieldFacet3D extends SparseFacet3D implements BooleanFieldFacet3D { - private final Map relData = Maps.newLinkedHashMap(); + private final Map relData = Maps.newLinkedHashMap(); private final boolean defValue; - public SparseBooleanFieldFacet3D(Region3i targetRegion, Border3D border) { + public SparseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border) { this(targetRegion, border, false); } - public SparseBooleanFieldFacet3D(Region3i targetRegion, Border3D border, boolean defValue) { + public SparseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border, boolean defValue) { super(targetRegion, border); this.defValue = defValue; } @@ -51,8 +50,8 @@ public boolean get(int x, int y, int z) { } @Override - public boolean get(Vector3i pos) { - checkRelativeCoords(pos.x, pos.y, pos.z); + public boolean get(Vector3ic pos) { + checkRelativeCoords(pos.x(), pos.y(), pos.z()); Boolean boxed = relData.get(pos); return (boxed != null) ? boxed : defValue; @@ -64,8 +63,8 @@ public void set(int x, int y, int z, boolean value) { } @Override - public void set(Vector3i pos, boolean value) { - checkRelativeCoords(pos.x, pos.y, pos.z); + public void set(Vector3ic pos, boolean value) { + checkRelativeCoords(pos.x(), pos.y(), pos.z()); if (value != defValue) { relData.put(pos, value); @@ -73,8 +72,8 @@ public void set(Vector3i pos, boolean value) { } @Override - public boolean getWorld(Vector3i pos) { - return getWorld(pos.x, pos.y, pos.z); + public boolean getWorld(Vector3ic pos) { + return getWorld(pos.x(), pos.y(), pos.z()); } @Override @@ -87,8 +86,8 @@ public boolean getWorld(int x, int y, int z) { } @Override - public void setWorld(Vector3i pos, boolean value) { - setWorld(pos.x, pos.y, pos.z, value); + public void setWorld(Vector3ic pos, boolean value) { + setWorld(pos.x(), pos.y(), pos.z(), value); } @Override @@ -104,7 +103,7 @@ public void setWorld(int x, int y, int z, boolean value) { /** * @return an unmodifiable view on the relative entries */ - public Map getRelativeEntries() { + public Map getRelativeEntries() { return Collections.unmodifiableMap(relData); } @@ -115,9 +114,9 @@ public Map getWorldEntries() { Map result = Maps.newLinkedHashMap(); - for (Entry entry : relData.entrySet()) { - Vector3i relPos = entry.getKey(); - Vector3i worldPos = relativeToWorld(relPos.x, relPos.y, relPos.z); + for (Entry entry : relData.entrySet()) { + Vector3ic relPos = entry.getKey(); + Vector3i worldPos = relativeToWorld(relPos.x(), relPos.y(), relPos.z()); result.put(worldPos, entry.getValue()); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java index 222e97243b5..4fa7754872b 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java @@ -16,33 +16,31 @@ package org.terasology.world.generation.facets.base; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; /** - * A base class for sparse (map-based) - * implementations of {@link WorldFacet3D}. - * + * A base class for sparse (map-based) implementations of {@link WorldFacet3D}. */ public abstract class SparseFacet3D implements WorldFacet3D { - private Region3i worldRegion; - private Region3i relativeRegion; + private BlockRegion worldRegion; + private BlockRegion relativeRegion; - public SparseFacet3D(Region3i targetRegion, Border3D border) { + public SparseFacet3D(BlockRegion targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); - relativeRegion = border.expandTo3D(targetRegion.size()); + relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); } @Override - public final Region3i getWorldRegion() { + public final BlockRegion getWorldRegion() { return worldRegion; } @Override - public final Region3i getRelativeRegion() { + public final BlockRegion getRelativeRegion() { return relativeRegion; } @@ -50,7 +48,7 @@ public final Region3i getRelativeRegion() { * @throws IllegalArgumentException if not within bounds */ protected void checkWorldCoords(int x, int y, int z) { - if (!worldRegion.encompasses(x, y, z)) { + if (!worldRegion.contains(x, y, z)) { String text = "Out of bounds: (%d, %d, %d) for region %s"; String msg = String.format(text, x, y, z, worldRegion.toString()); throw new IllegalArgumentException(msg); @@ -61,7 +59,7 @@ protected void checkWorldCoords(int x, int y, int z) { * @throws IllegalArgumentException if not within bounds */ protected void checkRelativeCoords(int x, int y, int z) { - if (!relativeRegion.encompasses(x, y, z)) { + if (!relativeRegion.contains(x, y, z)) { String text = "Out of bounds: (%d, %d, %d) for region %s"; String msg = String.format(text, x, y, z, relativeRegion.toString()); throw new IllegalArgumentException(msg); @@ -86,9 +84,9 @@ protected final Vector3i relativeToWorld(int x, int y, int z) { @Override public String toString() { - Vector3i worldMin = getWorldRegion().min(); - Vector3i relMin = getRelativeRegion().min(); - Vector3i size = getRelativeRegion().size(); + Vector3i worldMin = getWorldRegion().getMin(new Vector3i()); + Vector3i relMin = getRelativeRegion().getMin(new Vector3i()); + Vector3i size = getRelativeRegion().getSize(new Vector3i()); return String.format("SparseFacet3D [worldMin=%s, relativeMin=%s, size=%s]", worldMin, relMin, size); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java index bc7715cfb90..d3321b4c6fc 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java @@ -17,8 +17,9 @@ package org.terasology.world.generation.facets.base; import com.google.common.collect.Maps; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -33,15 +34,15 @@ public abstract class SparseFieldFacet3D extends SparseFacet3D implements FieldFacet3D { // msteiger: it could be advantageous to use a Joda Collections map instead - private final Map relData = Maps.newLinkedHashMap(); + private final Map relData = Maps.newLinkedHashMap(); private final float defValue; - public SparseFieldFacet3D(Region3i targetRegion, Border3D border) { + public SparseFieldFacet3D(BlockRegion targetRegion, Border3D border) { this(targetRegion, border, 0); } - public SparseFieldFacet3D(Region3i targetRegion, Border3D border, float defValue) { + public SparseFieldFacet3D(BlockRegion targetRegion, Border3D border, float defValue) { super(targetRegion, border); this.defValue = defValue; } @@ -52,8 +53,8 @@ public float get(int x, int y, int z) { } @Override - public float get(Vector3i pos) { - checkRelativeCoords(pos.x, pos.y, pos.z); + public float get(Vector3ic pos) { + checkRelativeCoords(pos.x(), pos.y(), pos.z()); Number n = relData.get(pos); return (n != null) ? n.floatValue() : defValue; @@ -65,7 +66,7 @@ public void set(int x, int y, int z, float value) { } @Override - public void set(Vector3i pos, float value) { + public void set(Vector3ic pos, float value) { set(pos, Float.valueOf(value)); } @@ -73,8 +74,8 @@ public void set(int x, int y, int z, Number value) { set(new Vector3i(x, y, z), value); } - public void set(Vector3i pos, Number value) { - checkRelativeCoords(pos.x, pos.y, pos.z); + public void set(Vector3ic pos, Number value) { + checkRelativeCoords(pos.x(), pos.y(), pos.z()); if (value.floatValue() != defValue) { relData.put(pos, value); @@ -82,8 +83,8 @@ public void set(Vector3i pos, Number value) { } @Override - public float getWorld(Vector3i pos) { - return getWorld(pos.x, pos.y, pos.z); + public float getWorld(Vector3ic pos) { + return getWorld(pos.x(), pos.y(), pos.z()); } @Override @@ -96,8 +97,8 @@ public float getWorld(int x, int y, int z) { } @Override - public void setWorld(Vector3i pos, float value) { - setWorld(pos.x, pos.y, pos.z, value); + public void setWorld(Vector3ic pos, float value) { + setWorld(pos.x(), pos.y(), pos.z(), value); } @Override @@ -105,8 +106,8 @@ public void setWorld(int x, int y, int z, float value) { setWorld(x, y, z, Float.valueOf(value)); } - public void setWorld(Vector3i pos, Number value) { - setWorld(pos.x, pos.y, pos.z, value); + public void setWorld(Vector3ic pos, Number value) { + setWorld(pos.x(), pos.y(), pos.z(), value); } public void setWorld(int x, int y, int z, Number value) { @@ -121,7 +122,7 @@ public void setWorld(int x, int y, int z, Number value) { /** * @return an unmodifiable view on the relative entries */ - public Map getRelativeEntries() { + public Map getRelativeEntries() { return Collections.unmodifiableMap(relData); } @@ -132,9 +133,9 @@ public Map getWorldEntries() { Map result = Maps.newLinkedHashMap(); - for (Entry entry : relData.entrySet()) { - Vector3i relPos = entry.getKey(); - Vector3i worldPos = relativeToWorld(relPos.x, relPos.y, relPos.z); + for (Entry entry : relData.entrySet()) { + Vector3ic relPos = entry.getKey(); + Vector3i worldPos = relativeToWorld(relPos.x(), relPos.y(), relPos.z()); result.put(worldPos, entry.getValue()); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java index 164e75f0174..3e00ceecb1d 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java @@ -17,10 +17,9 @@ package org.terasology.world.generation.facets.base; import com.google.common.collect.Maps; - -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -34,13 +33,13 @@ */ public abstract class SparseObjectFacet3D extends SparseFacet3D implements ObjectFacet3D { - private final Map relData = Maps.newLinkedHashMap(); + private final Map relData = Maps.newLinkedHashMap(); /** * @param targetRegion * @param border */ - public SparseObjectFacet3D(Region3i targetRegion, Border3D border) { + public SparseObjectFacet3D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); } @@ -50,7 +49,7 @@ public T get(int x, int y, int z) { } @Override - public T get(BaseVector3i pos) { + public T get(Vector3ic pos) { checkRelativeCoords(pos.x(), pos.y(), pos.z()); return relData.get(pos); @@ -62,14 +61,14 @@ public void set(int x, int y, int z, T value) { } @Override - public void set(BaseVector3i pos, T value) { + public void set(Vector3ic pos, T value) { checkRelativeCoords(pos.x(), pos.y(), pos.z()); relData.put(pos, value); // TODO: consider using an immutable vector here } @Override - public T getWorld(BaseVector3i pos) { + public T getWorld(Vector3ic pos) { return getWorld(pos.x(), pos.y(), pos.z()); } @@ -82,7 +81,7 @@ public T getWorld(int x, int y, int z) { } @Override - public void setWorld(BaseVector3i pos, T value) { + public void setWorld(Vector3ic pos, T value) { setWorld(pos.x(), pos.y(), pos.z(), value); } @@ -97,20 +96,20 @@ public void setWorld(int x, int y, int z, T value) { /** * @return an unmodifiable view on the relative entries */ - public Map getRelativeEntries() { + public Map getRelativeEntries() { return Collections.unmodifiableMap(relData); } /** * @return a new map with world-based position entries */ - public Map getWorldEntries() { + public Map getWorldEntries() { - Map result = Maps.newLinkedHashMap(); + Map result = Maps.newLinkedHashMap(); - for (Entry entry : relData.entrySet()) { - BaseVector3i relPos = entry.getKey(); - BaseVector3i worldPos = relativeToWorld(relPos.x(), relPos.y(), relPos.z()); + for (Entry entry : relData.entrySet()) { + Vector3ic relPos = entry.getKey(); + Vector3ic worldPos = relativeToWorld(relPos.x(), relPos.y(), relPos.z()); result.put(worldPos, entry.getValue()); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java index 2af8f57062c..6524ccd7773 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java @@ -5,8 +5,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; @@ -19,26 +18,26 @@ */ public class VerticallySparseBooleanFacet3D implements WorldFacet3D { - private Region3i worldRegion; - private Region3i relativeRegion; + private BlockRegion worldRegion; + private BlockRegion relativeRegion; private Set[] data; - public VerticallySparseBooleanFacet3D(Region3i targetRegion, Border3D border) { + public VerticallySparseBooleanFacet3D(BlockRegion targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); - relativeRegion = border.expandTo3D(targetRegion.size()); - data = new Set[worldRegion.sizeX() * worldRegion.sizeZ()]; + relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); + data = new Set[worldRegion.getSizeX() * worldRegion.getSizeZ()]; for (int i = 0; i < data.length; i++) { data[i] = new HashSet(); } } @Override - public Region3i getWorldRegion() { + public BlockRegion getWorldRegion() { return worldRegion; } @Override - public Region3i getRelativeRegion() { + public BlockRegion getRelativeRegion() { return relativeRegion; } @@ -92,16 +91,16 @@ public Set getWorldColumn(int x, int z) { } protected final int getRelativeIndex(Vector3ic pos) { - if (!relativeRegion.encompasses(JomlUtil.from(pos))) { + if (!relativeRegion.contains(pos)) { throw new IllegalArgumentException(String.format("Out of bounds: %s for region %s", pos.toString(), relativeRegion.toString())); } - return pos.x() - relativeRegion.minX() + relativeRegion.sizeX() * (pos.z() - relativeRegion.minZ()); + return pos.x() - relativeRegion.minX() + relativeRegion.getSizeX() * (pos.z() - relativeRegion.minZ()); } protected final int getWorldIndex(Vector3ic pos) { - if (!worldRegion.encompasses(JomlUtil.from(pos))) { + if (!worldRegion.contains(pos)) { throw new IllegalArgumentException(String.format("Out of bounds: %s for region %s", pos.toString(), worldRegion.toString())); } - return pos.x() - worldRegion.minX() + worldRegion.sizeX() * (pos.z() - worldRegion.minZ()); + return pos.x() - worldRegion.minX() + worldRegion.getSizeX() * (pos.z() - worldRegion.minZ()); } } diff --git a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java index 41d07d9f86b..e1798eb02d1 100644 --- a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java +++ b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java @@ -22,6 +22,7 @@ import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.time.WorldTime; import java.util.Collection; @@ -148,7 +149,7 @@ public WorldTime getTime() { } @Override - public Collection getRelevantRegions() { + public Collection getRelevantRegions() { return base.getRelevantRegions(); } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java index 8b358c51233..a618477e629 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java @@ -22,6 +22,7 @@ import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.time.WorldTime; import java.util.Collection; @@ -199,6 +200,6 @@ default Map setBlocks(Map blocks) { /** * @return an unmodifiable view on the generated relevant regions */ - Collection getRelevantRegions(); + Collection getRelevantRegions(); } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index bedfdf91f5f..5507feaaca3 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -20,6 +20,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.WorldComponent; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.CoreChunk; @@ -350,9 +351,9 @@ public WorldTime getTime() { } @Override - public Collection getRelevantRegions() { + public Collection getRelevantRegions() { Collection chunks = chunkProvider.getAllChunks(); - Function mapping = CoreChunk::getRegion; + Function mapping = CoreChunk::getRegion; Predicate isReady = ManagedChunk::isReady; diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java index 2bbb0a882f8..6786e421d2f 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java @@ -24,6 +24,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.WorldProvider; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import java.math.RoundingMode; @@ -162,7 +163,7 @@ public void unregisterListener(WorldChangeListener listener) { } @Override - public Collection getRelevantRegions() { + public Collection getRelevantRegions() { return core.getRelevantRegions(); } } From 45e3799f7d95fda53ebb692ccb3d650a1f3d1462 Mon Sep 17 00:00:00 2001 From: jdrueckert Date: Sun, 27 Dec 2020 00:53:18 +0100 Subject: [PATCH 041/259] doc: add system requirements to README (#4332) --- README.markdown | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index cdbd9b5965e..525858a42ff 100644 --- a/README.markdown +++ b/README.markdown @@ -27,7 +27,47 @@ We encourage contributions from anybody and try to keep a warm and friendly comm ## Playing -Make sure that your graphics card driver is up to date. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Minimum RequirementsRecommended Requirements
System (OS)Windows, MacOS, Linux (64 bit)
Processor (CPU)dual-core CPUquad-core CPU
Memory (RAM)2 GB8 GB
Graphics (GPU) + Intel HD Graphics (Gen 5)
+ GeForce 6xxx series or
+ Radeon HD 2000 series
+ with OpenGL 2.1* +
+ GeForce 8xxx series (or higher) or
+ Radeon HD 2000 series (or higher)
+ with OpenGL 3.x +
Storage (HDD)1 GB
+ +Internet connectivity is required for downloading Terasology via the Launcher, afterwards offline play is possible. For easy game setup (recommended) you can use our launcher - [download it here.](https://github.com/MovingBlocks/TerasologyLauncher/releases) From 3293a9812a143bc251b91ad56cf3785cd1dcac9a Mon Sep 17 00:00:00 2001 From: Josephine Rueckert Date: Sun, 27 Dec 2020 01:19:41 +0100 Subject: [PATCH 042/259] fix: make use of constant vectors and blockregion --- .../logic/characters/CharacterTeleportEvent.java | 7 ++++--- .../java/org/terasology/world/generation/Border3D.java | 5 +++-- .../world/generation/facets/base/BaseFacet3D.java | 3 ++- .../world/generation/facets/base/BaseFieldFacet3D.java | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterTeleportEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterTeleportEvent.java index e90f8ccc835..e5067d9ab33 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterTeleportEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterTeleportEvent.java @@ -16,6 +16,7 @@ package org.terasology.logic.characters; import org.joml.Vector3f; +import org.joml.Vector3fc; import org.terasology.entitySystem.event.Event; /** @@ -23,13 +24,13 @@ * movement prediction. */ public class CharacterTeleportEvent implements Event { - private Vector3f targetPosition; + private Vector3fc targetPosition; - public CharacterTeleportEvent(Vector3f targetPosition) { + public CharacterTeleportEvent(Vector3fc targetPosition) { this.targetPosition = targetPosition; } - public Vector3f getTargetPosition() { + public Vector3fc getTargetPosition() { return targetPosition; } } diff --git a/engine/src/main/java/org/terasology/world/generation/Border3D.java b/engine/src/main/java/org/terasology/world/generation/Border3D.java index 38c3d6edae8..4a4928bf240 100644 --- a/engine/src/main/java/org/terasology/world/generation/Border3D.java +++ b/engine/src/main/java/org/terasology/world/generation/Border3D.java @@ -19,6 +19,7 @@ import org.joml.Vector3i; import org.terasology.math.geom.Rect2i; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import java.util.Objects; @@ -85,13 +86,13 @@ public Rect2i expandTo2D(Vector3i size) { * @param region The region to be expanded with the borders. * @return The 3D world representation with the additional space added to it in the 3 dimensions. */ - public BlockRegion expandTo3D(BlockRegion region) { + public BlockRegion expandTo3D(BlockRegionc region) { return new BlockRegion(region.minX() - sides, region.minY() - bottom, region.minZ() - sides, region.maxX() + sides, region.maxY() + top, region.maxZ() + sides); } /** - * Same as {@code {@link #expandTo3D(BlockRegion)}}} but with a Vector3i instead of a Region3i. + * Same as {@code {@link #expandTo3D(BlockRegionc)}}} but with a Vector3i instead of a Region3i. * @param size The size to be used. * @return The 3D world representation with the additional space added to it in the 3 dimensions. */ diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java index 7775d5a9d8c..a6940546145 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet3D.java @@ -17,6 +17,7 @@ import org.joml.Vector3i; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; @@ -27,7 +28,7 @@ public class BaseFacet3D implements WorldFacet3D { private BlockRegion worldRegion; private BlockRegion relativeRegion; - public BaseFacet3D(BlockRegion targetRegion, Border3D border) { + public BaseFacet3D(BlockRegionc targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java index 476343434e7..cacfff55f5b 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet3D.java @@ -19,6 +19,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; /** @@ -27,7 +28,7 @@ public abstract class BaseFieldFacet3D extends BaseFacet3D implements FieldFacet private float[] data; - public BaseFieldFacet3D(BlockRegion targetRegion, Border3D border) { + public BaseFieldFacet3D(BlockRegionc targetRegion, Border3D border) { super(targetRegion, border); this.data = new float[getRelativeRegion().volume()]; } From 1d7ae967d6440ea22d9635c84c23ded6b6848e32 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Sun, 27 Dec 2020 14:20:40 +0000 Subject: [PATCH 043/259] fix(world): Compute border requests from rasterizers and `@Updates` annotations. (#4313) --- .../terasology/world/generation/Border3D.java | 33 +++-- .../world/generation/WorldBuilder.java | 122 +++++++----------- 2 files changed, 74 insertions(+), 81 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/generation/Border3D.java b/engine/src/main/java/org/terasology/world/generation/Border3D.java index 4a4928bf240..2e42169f4f4 100644 --- a/engine/src/main/java/org/terasology/world/generation/Border3D.java +++ b/engine/src/main/java/org/terasology/world/generation/Border3D.java @@ -46,6 +46,10 @@ public Border3D(int top, int bottom, int sides) { this.sides = sides; } + public Border3D(FacetBorder border) { + this(border.top(), border.bottom(), border.sides()); + } + /**@return Returns the extra space at the top. */ public int getTop() { return top; @@ -113,19 +117,30 @@ public Border3D extendBy(int topExtension, int bottomExtension, int sidesExtensi return new Border3D(top + topExtension, bottom + bottomExtension, sides + sidesExtension); } + /** + * Extends the border by using the sizes of another border. + * @param other The border to add to this one + * @return The new border with the extra extensions. + */ + public Border3D extendBy(Border3D other) { + return new Border3D(top + other.top, bottom + other.bottom, sides + other.sides); + } + /** * Returns a new border, using the largest value of each extension for both borders. Border A(Sides=5,Bottom=4,Top=3) maxed with border B (Sides=3,Bottom=4,Top=5) * would make a border C with boundries: (5,4,5). - * @param topValue The top value to compare with the instance's top value. - * @param bottomValue The bottom value to compare with the instance's bottom value. - * @param sidesValue The sides value to compare with the instance's sides value. - * @return The resulting Border3D. + * @param other The top value to compare with the instance's top value. + * @return The resulting new Border3D. */ - public Border3D maxWith(int topValue, int bottomValue, int sidesValue) { - return new Border3D( - Math.max(top, topValue), - Math.max(bottom, bottomValue), - Math.max(sides, sidesValue)); + public Border3D maxWith(Border3D other) { + if (other == null) { + return new Border3D(top, bottom, sides); + } else { + return new Border3D( + Math.max(top, other.top), + Math.max(bottom, other.bottom), + Math.max(sides, other.sides)); + } } /** diff --git a/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java b/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java index 629ca957b85..ad4302d7f55 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java @@ -104,93 +104,71 @@ public World build() { } ListMultimap, FacetProvider> providerChains = determineProviderChains(); List orderedRasterizers = ensureRasterizerOrdering(); - return new WorldImpl(providerChains, orderedRasterizers, entityProviders, determineBorders(providerChains), seaLevel); + return new WorldImpl(providerChains, orderedRasterizers, entityProviders, determineBorders(providerChains, orderedRasterizers), seaLevel); } - private Map, Border3D> determineBorders(ListMultimap, FacetProvider> providerChains) { + private Map, Border3D> determineBorders(ListMultimap, FacetProvider> providerChains, List worldRasterizers) { + List orderedProviders = new ArrayList<>(); + for (Class facet : providerChains.keySet()) { + for (FacetProvider provider : providerChains.get(facet)) { + if (!orderedProviders.contains(provider)) { + orderedProviders.add(provider); + } + } + } Map, Border3D> borders = Maps.newHashMap(); - for (Class facet : providerChains.keySet()) { - ensureBorderCalculatedForFacet(facet, providerChains, borders); + for (WorldRasterizer rasterizer : worldRasterizers) { + Requires requires = rasterizer.getClass().getAnnotation(Requires.class); + if (requires != null) { + for (Facet facet : requires.value()) { + borders.put(facet.value(), new Border3D(facet.border()).maxWith(borders.get(facet.value()))); + } + } } - return borders; - } + for (int i = orderedProviders.size() - 1; i >= 0; i--) { + FacetProvider provider = orderedProviders.get(i); + Border3D requiredBorder = new Border3D(0, 0, 0); + Requires requires = provider.getClass().getAnnotation(Requires.class); + Produces produces = provider.getClass().getAnnotation(Produces.class); + Updates updates = provider.getClass().getAnnotation(Updates.class); - private void ensureBorderCalculatedForFacet(Class facet, ListMultimap, FacetProvider> providerChains, - Map, Border3D> borders) { - - if (!borders.containsKey(facet)) { - - Border3D border = new Border3D(0, 0, 0); - int maxSide = 0; - int maxTop = 0; - int maxBottom = 0; - for (FacetProvider facetProvider : providerChains.values()) { - // Find all facets that require it - Requires requires = facetProvider.getClass().getAnnotation(Requires.class); - Produces produces = facetProvider.getClass().getAnnotation(Produces.class); - Updates updates = facetProvider.getClass().getAnnotation(Updates.class); - if (requires != null) { - for (Facet requiredFacet : requires.value()) { - if (requiredFacet.value() == facet) { - - - FacetBorder requiredBorder = requiredFacet.border(); - - if (produces != null) { - for (Class producedFacet : produces.value()) { - ensureBorderCalculatedForFacet(producedFacet, providerChains, borders); - Border3D borderForProducedFacet = borders.get(producedFacet); - border = border.maxWith( - borderForProducedFacet.getTop() + requiredBorder.top(), - borderForProducedFacet.getBottom() + requiredBorder.bottom(), - borderForProducedFacet.getSides() + requiredBorder.sides()); - } - } - if (updates != null) { - for (Facet producedFacetAnnotation : updates.value()) { - Class producedFacet = producedFacetAnnotation.value(); - FacetBorder borderForFacetAnnotation = producedFacetAnnotation.border(); - ensureBorderCalculatedForFacet(producedFacet, providerChains, borders); - Border3D borderForProducedFacet = borders.get(producedFacet); - border = border.maxWith( - borderForProducedFacet.getTop() + requiredBorder.top() + borderForFacetAnnotation.top(), - borderForProducedFacet.getBottom() + requiredBorder.bottom() + borderForFacetAnnotation.bottom(), - borderForProducedFacet.getSides() + requiredBorder.sides() + borderForFacetAnnotation.sides()); - } - } - } + // Calculate how large a region needs to be correct in the output + if (produces != null) { + for (Class facet : produces.value()) { + Border3D facetBorder = borders.get(facet); + if (facetBorder != null) { + requiredBorder = requiredBorder.maxWith(facetBorder); } } -//Get biggest border for facet?! Create an array of borders and search for maximum. -// Check if there are update annotation for facet, if there are search for biggest border requested from providers and replace value - if (updates != null) { - for (Facet producedFacetAnnotation : updates.value()) { - if (producedFacetAnnotation.value() == facet) { - - FacetBorder borderForFacetAnnotation = producedFacetAnnotation.border(); - if (maxSide < borderForFacetAnnotation.sides()) { - maxSide = borderForFacetAnnotation.sides(); - } - if (maxTop < borderForFacetAnnotation.top()) { - maxTop = borderForFacetAnnotation.top(); - } - if (maxBottom < borderForFacetAnnotation.bottom()) { - maxBottom = borderForFacetAnnotation.bottom(); - } - - } - + } + if (updates != null) { + for (Facet facet : updates.value()) { + Border3D facetBorder = borders.get(facet.value()); + if (facetBorder != null) { + requiredBorder = requiredBorder.maxWith(facetBorder); } + } + } - border = border.maxWith(maxTop, maxBottom, maxSide); + // Convert that to how large a region needs to be correct in the input. + if (updates != null) { + for (Facet facet : updates.value()) { + Border3D facetBorder = requiredBorder.extendBy(new Border3D(facet.border())); + borders.put(facet.value(), facetBorder.maxWith(borders.get(facet.value()))); + } + } + if (requires != null) { + for (Facet facet : requires.value()) { + Border3D facetBorder = requiredBorder.extendBy(new Border3D(facet.border())); + borders.put(facet.value(), facetBorder.maxWith(borders.get(facet.value()))); } } - borders.put(facet, border); } - } + return borders; + } private ListMultimap, FacetProvider> determineProviderChains() { ListMultimap, FacetProvider> result = ArrayListMultimap.create(); From 691aac09a5027b085585477a1a313a059d5a43ff Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 27 Dec 2020 09:13:34 -0800 Subject: [PATCH 044/259] feat: add BlockArea to replace Rect2i (#4050) Co-authored-by: Tobias Nett --- .../terasology/world/block/BlockAreaTest.java | 133 +++++ .../org/terasology/world/block/BlockArea.java | 357 ++++++++++++ .../terasology/world/block/BlockAreac.java | 527 ++++++++++++++++++ 3 files changed, 1017 insertions(+) create mode 100644 engine-tests/src/test/java/org/terasology/world/block/BlockAreaTest.java create mode 100644 engine/src/main/java/org/terasology/world/block/BlockArea.java create mode 100644 engine/src/main/java/org/terasology/world/block/BlockAreac.java diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockAreaTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockAreaTest.java new file mode 100644 index 00000000000..3d98dfceebd --- /dev/null +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockAreaTest.java @@ -0,0 +1,133 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.block; + +import org.joml.Vector2i; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Optional; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class BlockAreaTest { + + @Test + public void containsInvalid() { + BlockArea a = new BlockArea(BlockArea.INVALID); + assertFalse(a.contains(1, 0)); + assertFalse(a.contains(0, 1)); + assertFalse(a.contains(1, 1)); + assertFalse(a.contains(-1, 0)); + assertFalse(a.contains(0, -1)); + assertFalse(a.contains(-1, 1)); + assertFalse(a.contains(1, -1)); + assertFalse(a.contains(-1, -1)); + } + + @Test + public void testContains() { + BlockArea a = new BlockArea(1, 2, 3, 4); + assertTrue(a.contains(1, 2)); + assertTrue(a.contains(2, 3)); + assertTrue(a.contains(2, 4)); + assertFalse(a.contains(4, 3)); + assertFalse(a.contains(2, 5)); + assertFalse(a.contains(3, 5)); + } + + @Test + public void testContainsBlockRegion() { + BlockArea a = new BlockArea(1, 2, 10, 20); + + assertTrue(a.contains(new BlockArea(5, 5, 5, 5))); + assertFalse(a.contains(new BlockArea(11, 5, 35, 5))); + assertFalse(a.contains(new BlockArea(1, 21, 5, 95))); + + assertTrue(a.contains(new BlockArea(1, 2, 3, 3))); + assertTrue(a.contains(new BlockArea(4, 2, 8, 8))); + assertTrue(a.contains(new BlockArea(1, 4, 8, 8))); + assertTrue(a.contains(new BlockArea(5, 12, 9, 19))); + assertTrue(a.contains(new BlockArea(5, 12, 10, 20))); + assertFalse(a.contains(new BlockArea(5, 12, 10, 21))); + assertFalse(a.contains(new BlockArea(5, 12, 11, 20))); + } + + @Test + public void textExtents() { + BlockArea area = new BlockArea(2, 1, 10, 20).expand(3, 4); + assertEquals(new Vector2i(-1, -3), area.getMin(new Vector2i())); + assertEquals(new Vector2i(13, 24), area.getMax(new Vector2i())); + } + + @Test + public void testInvalidExtents() { + final BlockArea area = new BlockArea(0, 0, 3, 3); + assertThrows(IllegalArgumentException.class, () -> area.expand(-2, 1)); + assertThrows(IllegalArgumentException.class, () -> area.expand(1, -2)); + assertThrows(IllegalArgumentException.class, () -> area.expand(-2, -2)); + } + + @Test + public void testInvalidMinMax() { + assertThrows(IllegalArgumentException.class, () -> new BlockArea(0, 3).setMax(3, 0)); + assertThrows(IllegalArgumentException.class, () -> new BlockArea(3, 0).setMin(0, 3)); + assertThrows(IllegalArgumentException.class, () -> new BlockArea(0, 3, 3, 0)); + } + + static Stream testIntersectionWithAreaArgs() { + return Stream.of( + Arguments.of( + new BlockArea(0, 0, 2, 2), + new BlockArea(0, 0, 2, 2), + new BlockArea(0, 0, 2, 2) + ), + Arguments.of( + new BlockArea(0, 0, 2, 2), + new BlockArea(1, 1, 3, 3), + new BlockArea(1, 1, 2, 2) + ), + Arguments.of( + new BlockArea(0, 0, 2, 2), + new BlockArea(0, 2, 3, 3), + new BlockArea(0, 2, 2, 2) + ) + ); + } + + @ParameterizedTest + @MethodSource("testIntersectionWithAreaArgs") + public void testIntersectionWithArea(BlockArea a, BlockArea b, BlockArea expected) { + assertEquals(Optional.of(expected), a.intersect(b, new BlockArea())); + } + + static Stream testIntersectsAreaArgs() { + return Stream.of( + // positive cases + Arguments.of(new BlockArea(0, 0, 3, 3), true), + Arguments.of(new BlockArea(-1, -1, 4, 4), true), + Arguments.of(new BlockArea(-1, -1, 1, 1), true), + Arguments.of(new BlockArea(1, 1, 2, 2), true), + Arguments.of(new BlockArea(3, 1, 4, 2), true), + Arguments.of(new BlockArea(1, 3, 2, 4), true), + // negative cases + Arguments.of(new BlockArea(5, 5, 6, 6), false), + Arguments.of(new BlockArea(-2, -2, -1, -1), false), + Arguments.of(new BlockArea(), false) + ); + } + + @ParameterizedTest + @MethodSource("testIntersectsAreaArgs") + public void testIntersectsArea(BlockArea other, boolean intersecting) { + BlockArea area = new BlockArea(0, 0, 3, 3); + assertEquals(intersecting, area.intersectsBlockArea(other)); + } +} diff --git a/engine/src/main/java/org/terasology/world/block/BlockArea.java b/engine/src/main/java/org/terasology/world/block/BlockArea.java new file mode 100644 index 00000000000..37233792de1 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/block/BlockArea.java @@ -0,0 +1,357 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.block; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import org.joml.Math; +import org.joml.Vector2i; +import org.joml.Vector2ic; + +import java.util.Iterator; +import java.util.Optional; + +/** + * A mutable, bounded, axis-aligned are denoting a collection of blocks contained within. + */ +public class BlockArea implements BlockAreac { + + public static final BlockAreac INVALID = new BlockArea(); + + private int minX = Integer.MAX_VALUE; + private int minY = Integer.MAX_VALUE; + private int maxX = Integer.MIN_VALUE; + private int maxY = Integer.MIN_VALUE; + + // -- CONSTRUCTORS -----------------------------------------------------------------------------------------------// + + BlockArea() { + } + + public BlockArea(int minX, int minY, int maxX, int maxY) { + this.set(minX, minY, maxX, maxY); + } + + public BlockArea(Vector2ic min, Vector2ic max) { + this.set(min.x(), min.y(), max.x(), max.y()); + } + + public BlockArea(int x, int y) { + this.set(x, y, x, y); + } + + public BlockArea(Vector2ic pos) { + this.set(pos, pos); + } + + public BlockArea(BlockAreac other) { + this.set(other.minX(), other.minY(), other.maxX(), other.maxY()); + } + + // -- reset ------------------------------------------------------------------------------------------------------// + + public BlockArea set(int minX, int minY, int maxX, int maxY) { + Preconditions.checkArgument(minX <= maxX || (minX == INVALID.minX() && maxX == INVALID.maxX())); + Preconditions.checkArgument(minY <= maxY || (minY == INVALID.minY() && maxY == INVALID.maxY())); + + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + + return this; + } + + public BlockArea set(Vector2ic min, Vector2ic max) { + return this.set(min.x(), min.y(), max.x(), max.y()); + } + + public BlockArea set(BlockAreac other) { + return this.set(other.minX(), other.minY(), other.maxX(), other.maxY()); + } + + // -- ITERABLE ---------------------------------------------------------------------------------------------------// + + @Override + public Iterator iterator() { + return new Iterator() { + private Vector2i current = null; + private final Vector2i next = getMin(new Vector2i()); + + public boolean findNext() { + if (current.equals(next)) { + next.y++; + if (next.y > maxY) { + next.y = minY; + next.x++; + } + + return contains(next); + } + return true; + } + + @Override + public boolean hasNext() { + if (!isValid()) { + return false; + } + if (current == null) { + return true; + } + + if (current.equals(next)) { + return findNext(); + } + return contains(next); + } + + @Override + public Vector2ic next() { + if (current == null) { + current = new Vector2i(next); + return next; + } + + if (current.equals(next)) { + if (findNext()) { + return next; + } + return null; + } + current.set(next); + return next; + } + }; + } + + // -- GETTERS & SETTERS ------------------------------------------------------------------------------------------// + + @Override + public int minX() { + return minX; + } + + @Override + public int minY() { + return minY; + } + + @Override + public BlockArea minX(int x, BlockArea dest) { + return dest.set(x, minY, maxX, maxY); + } + + public BlockArea minX(int x) { + return minX(x, this); + } + + @Override + public BlockArea minY(int y, BlockArea dest) { + return dest.set(minX, y, maxX, maxY); + } + + public BlockArea minY(int y) { + return minY(y, this); + } + + @Override + public BlockArea setMin(int x, int y, BlockArea dest) { + return dest.set(x, y, maxX, maxY); + } + + public BlockArea setMin(int x, int y) { + return this.setMin(x, y, this); + } + + public BlockArea setMin(Vector2ic min) { + return this.setMin(min.x(), min.y(), this); + } + + public BlockArea addToMin(int x, int y) { + return this.addToMin(x, y, this); + } + + public BlockArea addToMin(Vector2ic min) { + return this.addToMin(min.x(), min.y(), this); + } + + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public int maxX() { + return maxX; + } + + @Override + public int maxY() { + return maxY; + } + + @Override + public BlockArea maxX(int x, BlockArea dest) { + return dest.set(minX, minY, x, maxY); + } + + public BlockArea maxX(int x) { + return maxX(x, this); + } + + @Override + public BlockArea maxY(int y, BlockArea dest) { + return dest.set(minX, minY, maxX, y); + } + + public BlockArea maxY(int y) { + return maxY(y, this); + } + + @Override + public BlockArea setMax(int x, int y, BlockArea dest) { + return dest.set(minX, minY, x, y); + } + + public BlockArea setMax(int x, int y) { + return this.setMax(x, y, this); + } + + public BlockArea setMax(Vector2ic max) { + return this.setMax(max.x(), max.y(), this); + } + + public BlockArea addToMax(int x, int y) { + return this.addToMax(x, y, this); + } + + public BlockArea addToMax(Vector2ic max) { + return this.addToMax(max.x(), max.y(), this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public BlockArea setSize(int sizeX, int sizeY, BlockArea dest) { + return dest.set(minX, minY, minX + sizeX - 1, minY + sizeY - 1); + } + + public BlockArea setSize(int sizeX, int sizeY) { + return this.setSize(sizeX, sizeY, this); + } + + public BlockArea setSize(Vector2ic size) { + return this.setSize(size.x(), size.y(), this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public BlockArea union(int x, int y, BlockArea dest) { + return dest.set( + Math.min(this.minX, x), Math.min(this.minY, y), + Math.max(this.maxX, x), Math.max(this.maxY, y)); + } + + public BlockArea union(int x, int y) { + return union(x, y, this); + } + + public BlockArea union(Vector2ic p) { + return union(p.x(), p.y(), this); + } + + public BlockArea union(BlockArea other) { + return union(other, this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public Optional intersect(BlockAreac other, BlockArea dest) { + dest.minX = Math.max(minX, other.minX()); + dest.minY = Math.max(minY, other.minY()); + + dest.maxX = Math.min(maxX, other.maxX()); + dest.maxY = Math.min(maxY, other.maxY()); + + if (dest.isValid()) { + return Optional.of(dest); + } else { + return Optional.empty(); + } + } + + public Optional intersect(BlockAreac other) { + return this.intersect(other, this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public BlockArea translate(int dx, int dy, BlockArea dest) { + dest.minX = minX + dx; + dest.minY = minY + dy; + dest.maxX = maxX + dx; + dest.maxY = maxY + dy; + return dest; + } + + public BlockArea translate(int dx, int dy) { + return translate(dx, dy, this); + } + + public BlockArea translate(Vector2ic dv) { + return translate(dv.x(), dv.y(), this); + } + + public BlockArea setPosition(int x, int y) { + return setPosition(x, y, this); + } + + public BlockArea setPosition(Vector2i pos) { + return setPosition(pos.x(), pos.y(), this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public BlockArea expand(int dx, int dy, BlockArea dest) { + return dest.set(minX - dx, minY - dy, maxX + dx, maxY + dy); + } + + public BlockArea expand(int dx, int dy) { + return expand(dx, dy, this); + } + + public BlockArea expand(Vector2ic dv) { + return expand(dv.x(), dv.y(), this); + } + + // ---------------------------------------------------------------------------------------------------------------// + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BlockArea blockArea = (BlockArea) o; + return minX == blockArea.minX + && minY == blockArea.minY + && maxX == blockArea.maxX + && maxY == blockArea.maxY; + } + + @Override + public int hashCode() { + return Objects.hashCode(minX, minY, maxX, maxY); + } + + @Override + public String toString() { + return "BlockArea[(" + this.minX + ", " + this.minY + ")...(" + this.maxX + ", " + this.maxY + ")]"; + } +} diff --git a/engine/src/main/java/org/terasology/world/block/BlockAreac.java b/engine/src/main/java/org/terasology/world/block/BlockAreac.java new file mode 100644 index 00000000000..eaaaf40da29 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/block/BlockAreac.java @@ -0,0 +1,527 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.block; + +import org.joml.Rectanglef; +import org.joml.Vector2f; +import org.joml.Vector2fc; +import org.joml.Vector2i; +import org.joml.Vector2ic; + +import java.util.Iterator; +import java.util.Optional; + +/** + * An immutable, bounded, axis-aligned are denoting a collection of blocks contained within. + */ +public interface BlockAreac extends Iterable { + + // -- ITERABLE ---------------------------------------------------------------------------------------------------// + + /** + * Iterate over the blocks in this block area, where the same {@link Vector2ic} is reused for low memory footprint. + *

+ * Do not store the elements directly or use them outside the context of the iterator as they will change when the + * iterator is advanced. You may create new vectors from the elements if necessary, e.g.: + *

+     *     for (Vector2ic p : area) {
+     *         Vector2i pos = new Vector2i(p);
+     *         // use 'pos' instead of 'p'
+     *     }
+     * 
+ */ + Iterator iterator(); + + // -- min -------------------------------------------------------------------------------------------------------// + + /** + * The x-coordinate of the minimum corner + */ + int minX(); + + /** + * The y-coordinate of the minimum corner + */ + int minY(); + + /** + * Get the block coordinate of the minimum corner. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector2i getMin(Vector2i dest) { + return dest.set(minX(), minY()); + } + + /** + * Set the minimum x-coordinate of the area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is greater than the maximum x coordinate + */ + BlockArea minX(int x, BlockArea dest); + + /** + * Set the minimum y-coordinate of the area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code y} is greater than the maximum y coordinate + */ + BlockArea minY(int y, BlockArea dest); + + /** + * Set the coordinates of the minimum corner for this area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is greater than the respective component of the maximum + * corner + */ + BlockArea setMin(int x, int y, BlockArea dest); + + /** + * Set the coordinates of the minimum corner for this area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is greater than the respective component of the maximum + * corner + */ + default BlockArea setMin(Vector2ic min, BlockArea dest) { + return this.setMin(min.x(), min.y(), dest); + } + + /** + * Translate the minimum corner of the area by adding given {@code (dx, dy)}. + * + * @param dx the number of blocks to add to the minimum corner on the x axis + * @param dy the number of blocks to add to the minimum corner on the y axis + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting area would be {@link #isValid() invalid}. + */ + default BlockArea addToMin(int dx, int dy, BlockArea dest) { + return this.setMin(minX() + dx, minY() + dy, dest); + } + + /** + * Translate the minimum corner of the area by adding given {@code (dx, dy)}. + * + * @param dmin the translation vector for the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting area would be {@link #isValid() invalid}. + */ + default BlockArea addToMin(Vector2ic dmin, BlockArea dest) { + return this.addToMin(dmin.x(), dmin.y(), dest); + } + + // -- max -------------------------------------------------------------------------------------------------------// + + /** + * The x-coordinate of the maximum corner + */ + int maxX(); + + /** + * The y-coordinate of the maximum corner + */ + int maxY(); + + /** + * Get the block coordinate of the maximum corner. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector2i getMax(Vector2i dest) { + return dest.set(maxX(), maxY()); + } + + /** + * Set the maximum x-coordinate of the area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is smaller than the minimum x-coordinate + */ + BlockArea maxX(int x, BlockArea dest); + + /** + * Set the maximum y-coordinate of the area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if {@code x} is smaller than the minimum x-coordinate + */ + BlockArea maxY(int y, BlockArea dest); + + /** + * Set the coordinates of the maximum corner for this area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is smaller than the respective component of the minimum + * corner + */ + BlockArea setMax(int x, int y, BlockArea dest); + + /** + * Set the coordinates of the maximum corner for this area. + * + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if any dimension is smaller than the respective component of the minimum + * corner + */ + default BlockArea setMax(Vector2ic max, BlockArea dest) { + return this.setMax(max.x(), max.y(), dest); + } + + /** + * Translate the maximum corner of the area by adding given {@code (dx, dy)}. + * + * @param dx the number of blocks to add to the maximum corner on the x axis + * @param dy the number of blocks to add to the maximum corner on the y axis + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting area would be {@link #isValid() invalid}. + */ + default BlockArea addToMax(int dx, int dy, BlockArea dest) { + return this.setMax(maxX() + dx, maxY() + dy, dest); + } + + /** + * Translate the maximum corner of the area by adding given {@code (dx, dy)}. + * + * @param dmax the translation vector for the maximum corner + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the resulting area would be {@link #isValid() invalid}. + */ + default BlockArea addToMax(Vector2ic dmax, BlockArea dest) { + return this.addToMax(dmax.x(), dmax.y(), dest); + } + + // -- size ------------------------------------------------------------------------------------------------------// + + /** + * The number of blocks on the x axis. + */ + default int getSizeX() { + return maxX() - minX() + 1; + } + + /** + * The number of blocks on the y axis. + */ + default int getSizeY() { + return maxY() - minY() + 1; + } + + /** + * The number of blocks in this area along the +x, +y axis from the minimum to the maximum corner. + * + * @param dest will hold the result + * @return dest + */ + default Vector2i getSize(Vector2i dest) { + return dest.set(getSizeX(), getSizeY()); + } + + /** + * Set the size of the block area from the minimum corner. + * + * @param x the x coordinate to set the size; must be > 0 + * @param y the y coordinate to set the size; must be > 0 + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the size is smaller than or equal to 0 in any dimension + */ + BlockArea setSize(int x, int y, BlockArea dest); + + /** + * Set the size of the block area from the minimum corner. + * + * @param size the size to set; all dimensions must be > 0 + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if the size is smaller than or equal to 0 in any dimension + */ + default BlockArea setSize(Vector2ic size, BlockArea dest) { + return this.setSize(size.x(), size.y(), dest); + } + + /** + * The are of this area in blocks, i.e., the number of blocks contained in this area. + *

+ * The area is computed by + *

+     *     area = sizeX * sizeY;
+     * 
+ * + * @return the area in blocks + */ + default int area() { + return getSizeX() * getSizeY(); + } + + // -- world -----------------------------------------------------------------------------------------------------// + + /** + * The bounding area in world coordinates. + *

+ * The bounding box of a single block at {@code (x, y)} is centered at the integer coordinate {@code (x, y)} and + * extents by {@code 0.5} in each dimension. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Rectanglef getBounds(Rectanglef dest) { + dest.minX = minX() - .5f; + dest.minY = minY() - .5f; + + dest.maxX = maxX() + .5f; + dest.maxY = maxY() + .5f; + + return dest; + } + + /** + * The center of the area in world coordinates if the area is valid; {@link Float#NaN} otherwise. + * + * @param dest will hold the result + * @return {@code dest} + */ + default Vector2f center(Vector2f dest) { + if (!this.isValid()) { + return dest.set(Float.NaN); + } + return dest.set( + (this.minX() - .5f) + ((this.maxX() - this.minX() + 1.0f) / 2.0f), + (this.minY() - .5f) + ((this.maxY() - this.minY() + 1.0f) / 2.0f) + ); + } + + // -- IN-PLACE MUTATION -----------------------------------------------------------------------------------------// + // -- union -----------------------------------------------------------------------------------------------------// + + /** + * Compute the union of this area and the given block coordinate. + * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + BlockArea union(int x, int y, BlockArea dest); + + /** + * Compute the union of this area and the given block coordinate. + * + * @param pos the position of the block + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockArea union(Vector2ic pos, BlockArea dest) { + return this.union(pos.x(), pos.y(), dest); + } + + /** + * Compute the union of this area and the other area. + * + * @param other {@link BlockArea} + * @param dest destination; will hold the result + * @return @code dest} (after modification) + */ + default BlockArea union(BlockAreac other, BlockArea dest) { + return this.union(other.minX(), other.minY(), dest) + .union(other.maxX(), other.maxY(), dest); + } + + // -- intersect -------------------------------------------------------------------------------------------------// + + /** + * Compute the intersection of this area with the {@code other} area. + *

+ * NOTE: If the areas don't intersect the destination area will become invalid! + * + * @param other the other area + * @param dest destination; will hold the result + * @return {@code dest} (after modification) or {@link Optional#empty()} if the areas don't intersect + */ + Optional intersect(BlockAreac other, BlockArea dest); + + // ---------------------------------------------------------------------------------------------------------------// + + /** + * Translate this area by the given vector {@code (x, y, z))}. + * + * @param dx the x coordinate to translate by + * @param dy the y coordinate to translate by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + BlockArea translate(int dx, int dy, BlockArea dest); + + /** + * Translate this area by the given vector {@code vec}. + * + * @param vec the vector to translate by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockArea translate(Vector2ic vec, BlockArea dest) { + return this.translate(vec.x(), vec.y(), dest); + } + + /** + * Move this area to the given position {@code (x, y)). The position is defined by the minimum corner. + * + * @param x the new x coordinate of the minimum corner + * @param y the new y coordinate of the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockArea setPosition(int x, int y, BlockArea dest) { + return this.translate(x - minX(), y - minY(), dest); + } + + /** + * Move this area to the given position {@code (x, y)). The position is defined by the minimum corner. + * + * @param pos the new coordinates of the minimum corner + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + */ + default BlockArea setPosition(Vector2ic pos, BlockArea dest) { + return this.setPosition(pos.x(), pos.y(), dest); + } + + // -- expand -----------------------------------------------------------------------------------------------------// + + /** + * Expand this area by adding the given {@code extents} for each face of the area. + * + * @param dx the amount of blocks to extend this area by along the x axis in both directions + * @param dy the amount of blocks to extend this area by along the y axis in both directions + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if extending this area would result in any non-positive dimension + */ + BlockArea expand(int dx, int dy, BlockArea dest); + + /** + * Expand this area by adding the given {@code extents} for each face of a area. + * + * @param vec the amount of blocks to expand this area by + * @param dest destination; will hold the result + * @return {@code dest} (after modification) + * @throws IllegalArgumentException if extending this area would result in any non-positive dimension + */ + default BlockArea expand(Vector2ic vec, BlockArea dest) { + return this.expand(vec.x(), vec.y(), dest); + } + + // -- transform --------------------------------------------------------------------------------------------------// + + //TODO: does this make sense for a BlockArea? + // BlockArea transform(Matrix4fc m, BlockArea dest); + + // -- CHECKS -----------------------------------------------------------------------------------------------------// + + /** + * Check whether this area is valid. + *

+ * A block area is valid iff the minimum corner is component-wise smaller or equal to the maximum corner. + * + * @return {@code true} iff this area is valid; {@code false} otherwise + */ + default boolean isValid() { + return minX() <= maxX() && minY() <= maxY(); + } + + // -- contains ---------------------------------------------------------------------------------------------------// + + /** + * Test whether the block {@code (x, y)} lies inside this area. + * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @return {@code true} iff the given point lies inside this area; {@code false} otherwise + */ + default boolean contains(int x, int y) { + return x >= minX() && y >= minY() && x <= maxX() && y <= maxY(); + } + + /** + * Test whether the block at position {@code pos} lies inside this area. + * + * @param pos the coordinates of the block + * @return {@code true} iff the given point lies inside this area; {@code false} otherwise + */ + default boolean contains(Vector2ic pos) { + return this.contains(pos.x(), pos.y()); + } + + /** + * Test whether the point {@code (x, y)} lies inside this area. + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @return {@code true} iff the given point lies inside this area; {@code false} otherwise + * @see #getBounds(Rectanglef) + */ + default boolean contains(float x, float y) { + return x >= (this.minX() - .5f) + && y >= (this.minY() - .5f) + && x <= (this.maxX() + .5f) + && y <= (this.maxY() + .5f); + } + + /** + * Test whether the {@code point} lies inside this area. + * + * @param point the coordinates of the point + * @return {@code true} iff the given point lies inside this area; {@code false} otherwise + */ + default boolean contains(Vector2fc point) { + return this.contains(point.x(), point.y()); + } + + /** + * Test whether the given area {@code other} is fully enclosed by this area. + * + * @param other the other area + * @return {@code true} iff the given area is fully enclosed by this area; {@code false} otherwise + */ + default boolean contains(BlockAreac other) { + return this.contains(other.minX(), other.minY()) + && this.contains(other.maxX(), other.maxY()); + } + + // -- intersects -------------------------------------------------------------------------------------------------// + + //TODO: which intersection tests make sense for BlockArea? + + /** + * Test whether this area and {@code other} intersect. + * + * @param other the other BlockArea + * @return {@code true} iff both areas intersect; {@code false} otherwise + */ + default boolean intersectsBlockArea(BlockAreac other) { + return this.maxX() >= other.minX() && this.maxY() >= other.minY() + && this.minX() <= other.maxX() && this.minY() <= other.maxY(); + } + + // ---------------------------------------------------------------------------------------------------------------// + public boolean equals(Object obj); + + public int hashCode(); + + public String toString(); +} From 4d11f89172b7a88692ea62962193c19ffb0db985 Mon Sep 17 00:00:00 2001 From: Rasmus Praestholm Date: Sun, 27 Dec 2020 23:54:11 -0600 Subject: [PATCH 045/259] fix: casing fix for homedir arg from Gradle (#4337) --- facades/PC/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 74fb7308370..36b1395b473 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -126,7 +126,7 @@ val commonConfigure : JavaExec.()-> Unit = { classpath(sourceSets["main"].runtimeClasspath) - args("-homeDir") + args("-homedir") jvmArgs("-Xmx1536m") if (isMacOS()) { From 211bea31765ba8994ce4e02677b7edb37443b806 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 06:07:13 -0800 Subject: [PATCH 046/259] build: save build time by not checking jcenter for terasology dependencies (#4342) * chore (build): remove old snowplow repo all our branches have had version >= 0.9 for a while now so this should be okay. * perf (build): don't ask jcenter for org.terasology dependencies this is an optimization to save a bunch of failed lookups while resolving the module dependency tree. --- config/gradle/common.gradle | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index 926387290a1..ba4c7d344b6 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -27,9 +27,16 @@ tasks.withType(JavaCompile) { // We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on repositories { - // External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case - jcenter() - mavenCentral() + // External libs - jcenter is Bintray and a superset of Maven Central + jcenter { + content { + // This is first choice for most java dependencies, but assume we'll need to check our + // own repository for things from our own organization. + // (This is an optimization so gradle doesn't try to find our hundreds of modules + // in jcenter.) + excludeGroupByRegex(/org\.terasology(\..+)?/) + } + } // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs maven { @@ -48,12 +55,6 @@ repositories { allowInsecureProtocol true // 😱 } } - - maven { - name "snowplow (pre-0.9)" - url "http://maven.snplow.com/releases" - allowInsecureProtocol true // 😱 - } } dependencies { From 94caff32dc65c696ed833d519cbbf1ffdb83596b Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 28 Dec 2020 06:34:36 -0800 Subject: [PATCH 047/259] feat(JOML): migrate to Rectanglei nui.animation (#4341) --- .../org/terasology/rendering/nui/CoreScreenLayer.java | 2 +- .../nui/animation/DeferredMenuAnimationSystem.java | 3 ++- .../rendering/nui/animation/MenuAnimationSystem.java | 4 ++-- .../nui/animation/MenuAnimationSystemStub.java | 4 ++-- .../nui/animation/SwipeMenuAnimationSystem.java | 10 +++++----- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java b/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java index d84fb813984..e82631442e9 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java @@ -202,7 +202,7 @@ public UIWidget getContents() { @Override public void onDraw(Canvas canvas) { - Rectanglei region = JomlUtil.from(animationSystem.animateRegion(JomlUtil.from(canvas.getRegion()))); + Rectanglei region = animationSystem.animateRegion(canvas.getRegion()); if (isModal()) { canvas.addInteractionRegion(getScreenListener(), region); } diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java index 05219fc21ff..a7b75f9a807 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java @@ -18,6 +18,7 @@ import java.util.function.Supplier; +import org.joml.Rectanglei; import org.terasology.math.geom.Rect2i; /** @@ -72,7 +73,7 @@ public void stop() { } @Override - public Rect2i animateRegion(Rect2i rc) { + public Rectanglei animateRegion(Rectanglei rc) { return getSystem().animateRegion(rc); } diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java index f8034f3f8b4..b1cc4af2a00 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.animation; -import org.terasology.math.geom.Rect2i; +import org.joml.Rectanglei; /** * Controls animations to and from different screens @@ -59,7 +59,7 @@ public interface MenuAnimationSystem { * @param rc the rect to transform * @return the transformed rectangle */ - Rect2i animateRegion(Rect2i rc); + Rectanglei animateRegion(Rectanglei rc); /** * Stops the current animation by skipping straight to the end diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java index 1013f55f05b..cb1c9cbcbb9 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.animation; -import org.terasology.math.geom.Rect2i; +import org.joml.Rectanglei; /** * Does not do anything. The {@link #onEnd(Runnable)} method is triggered instantly. @@ -66,7 +66,7 @@ public void skip() { } @Override - public Rect2i animateRegion(Rect2i rc) { + public Rectanglei animateRegion(Rectanglei rc) { return rc; } } diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java index b364c6e5155..8ebc91a62ae 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java @@ -15,6 +15,7 @@ */ package org.terasology.rendering.nui.animation; +import org.joml.Rectanglei; import org.terasology.math.geom.Rect2i; import org.terasology.rendering.animation.Animation; import org.terasology.rendering.animation.AnimationListener; @@ -194,14 +195,13 @@ public void update(float delta) { } @Override - public Rect2i animateRegion(Rect2i rc) { + public Rectanglei animateRegion(Rectanglei rc) { if (scale == 0.0) { // this should cover most of the cases return rc; } - - int left = (int) (direction.getHorzScale() * scale * rc.width()); - int top = (int) (direction.getVertScale() * scale * rc.height()); - return Rect2i.createFromMinAndSize(left, top, rc.width(), rc.height()); + int left = (int) (direction.getHorzScale() * scale * rc.lengthX()); + int top = (int) (direction.getVertScale() * scale * rc.lengthY()); + return new Rectanglei(left, top, left + rc.lengthX(), top + rc.lengthY()); } } From b8d7f2aae816723c26c599e57eb4c20c45c44325 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 27 Dec 2020 21:15:20 -0800 Subject: [PATCH 048/259] chore: use short-form copyright --- modules/subprojects.settings.gradle | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/modules/subprojects.settings.gradle b/modules/subprojects.settings.gradle index bc3467d19c6..570d905ca86 100644 --- a/modules/subprojects.settings.gradle +++ b/modules/subprojects.settings.gradle @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 // This magically allows subdirs in this subproject to themselves become sub-subprojects in a proper tree structure new File(rootDir, 'modules').eachDir { possibleSubprojectDir -> From 5cfcf10928f3c0e79cb5c1e8fbc78cfe578b79ee Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 27 Dec 2020 21:54:53 -0800 Subject: [PATCH 049/259] chore (build): refactor lambda to named function --- facades/PC/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 36b1395b473..518230b2757 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -113,7 +113,7 @@ configurations { } // Used for all game configs. -val commonConfigure : JavaExec.()-> Unit = { +fun JavaExec.commonConfigure() { group = "terasology run" dependsOn(":extractNatives") From ef739b4c18572fb61e61af6e605289d739f6654d Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 27 Dec 2020 22:15:26 -0800 Subject: [PATCH 050/259] fix (build): use gradle to resolve all runtime classpath for facades The :moduleClasses task wasn't sufficient to get all the dependencies of those classes on the classpath. This replaces it with a gradle Platform which depends on all those module subprojects. Fixes #4014. --- build.gradle | 4 ---- facades/PC/build.gradle.kts | 3 ++- facades/TeraEd/build.gradle | 3 ++- modules/build.gradle.kts | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 modules/build.gradle.kts diff --git a/build.gradle b/build.gradle index 1cc820e4f25..c986c48c023 100644 --- a/build.gradle +++ b/build.gradle @@ -190,14 +190,10 @@ def terasologyModules() { } // Helpers that do magic things after having dependencies attached below -task moduleClasses task moduleJars // This magically makes everything work - without this the desired module projects returned have no tasks :-( gradle.projectsEvaluated { - // Note how "classes" may indirectly trigger "jar" for module dependencies of modules (module compile dependency) - moduleClasses.dependsOn(terasologyModules().classes) - // This makes it work for a full jar task moduleJars.dependsOn(terasologyModules().jar) } diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 518230b2757..c7c9580e3e8 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -92,6 +92,8 @@ dependencies { // TODO: Consider whether we can move the CR dependency back here from the engine, where it is referenced from the main menu implementation(group = "org.terasology.crashreporter", name = "cr-terasology", version = "4.1.0") + + runtimeOnly(platform(project(":modules"))) } // Instructions for packaging a jar file for the PC facade @@ -117,7 +119,6 @@ fun JavaExec.commonConfigure() { group = "terasology run" dependsOn(":extractNatives") - dependsOn(":moduleClasses") dependsOn("classes") // Run arguments diff --git a/facades/TeraEd/build.gradle b/facades/TeraEd/build.gradle index 1e7cd56d860..be43aefd617 100644 --- a/facades/TeraEd/build.gradle +++ b/facades/TeraEd/build.gradle @@ -26,6 +26,8 @@ sourceSets { dependencies { implementation project(':engine') implementation group: 'org.reflections', name: 'reflections', version: '0.9.10' + + runtimeOnly(platform(project(":modules"))) } application { @@ -46,7 +48,6 @@ task editor(type:JavaExec) { // Dependencies: natives + all modules & the PC facade itself (which will trigger the engine) dependsOn rootProject.extractNatives - dependsOn rootProject.moduleClasses dependsOn classes // Run arguments diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts new file mode 100644 index 00000000000..27536de9e11 --- /dev/null +++ b/modules/build.gradle.kts @@ -0,0 +1,17 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +plugins { + `java-platform` +} + +javaPlatform { + allowDependencies() +} + +dependencies { + // This platform depends on each of its subprojects. + subprojects { + runtime(this) + } +} From e8214339e905955cba910b1a60027abdd971e4bd Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 09:41:25 -0800 Subject: [PATCH 051/259] feat (build): make :modules:clean clean each module --- modules/build.gradle.kts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts index 27536de9e11..d51022963af 100644 --- a/modules/build.gradle.kts +++ b/modules/build.gradle.kts @@ -15,3 +15,11 @@ dependencies { runtime(this) } } + +// Allows using :modules:clean as a shortcut for running clean in each module. +tasks.named("clean").configure { + val cleanPlatform = this + subprojects { + cleanPlatform.dependsOn(this.tasks.named("clean")) + } +} From 3b619523d3a21520633657ede8f5e7f864337080 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 28 Dec 2020 11:03:21 -0800 Subject: [PATCH 052/259] chore: remove SubSampledNoise2D/3D (#4334) --- .../procedural/SubSampledNoise2D.java | 121 --------------- .../procedural/SubSampledNoise3D.java | 146 ------------------ 2 files changed, 267 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise2D.java delete mode 100644 engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise3D.java diff --git a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise2D.java b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise2D.java deleted file mode 100644 index ee3087119f7..00000000000 --- a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise2D.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.utilities.procedural; - -import com.google.common.math.IntMath; - -import org.terasology.math.geom.Rect2i; -import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector2i; - -/** - * @deprecated Use {@link SubSampledNoise} instead - */ -@Deprecated -public class SubSampledNoise2D implements Noise2D { - - private Noise2D source; - private Vector2f zoom = new Vector2f(1, 1); - private int sampleRate = 1; - - public SubSampledNoise2D(Noise2D source, Vector2f zoom, int sampleRate) { - this.source = source; - this.zoom.set(zoom); - this.sampleRate = sampleRate; - } - - @Override - public float noise(float x, float y) { - float xMod = TeraMath.modulus(x, sampleRate); - float yMod = TeraMath.modulus(y, sampleRate); - - float x0 = x - xMod; - float x1 = x0 + sampleRate; - float y0 = y - yMod; - float y1 = y0 + sampleRate; - - float q00 = source.noise(x0 * zoom.x, y0 * zoom.y); - float q10 = source.noise(x1 * zoom.x, y0 * zoom.y); - float q01 = source.noise(x0 * zoom.x, y1 * zoom.y); - float q11 = source.noise(x1 * zoom.x, y1 * zoom.y); - - return TeraMath.biLerp(q00, q10, q01, q11, xMod / sampleRate, yMod / sampleRate); - } - - public float[] noise(Rect2i region) { - Rect2i fullRegion = determineRequiredRegion(region); - float[] keyData = getKeyValues(fullRegion); - float[] fullData = mapExpand(keyData, fullRegion); - return getSubset(fullData, fullRegion, region); - } - - private float[] getSubset(float[] fullData, Rect2i fullRegion, Rect2i subRegion) { - if (subRegion.size().x != fullRegion.size().x || subRegion.size().y != fullRegion.size().y) { - float[] result = new float[subRegion.size().x * subRegion.size().y]; - Vector2i offset = new Vector2i(subRegion.minX() - fullRegion.minX(), subRegion.minY() - fullRegion.minY()); - for (int y = 0; y < subRegion.size().y; ++y) { - System.arraycopy(fullData, offset.getX() + fullRegion.size().x * (y + offset.getY()), result, subRegion.size().x * y, subRegion.size().x); - } - return result; - } else { - return fullData; - } - } - - private float[] mapExpand(float[] keyData, Rect2i fullRegion) { - float[] fullData = new float[fullRegion.size().x * fullRegion.size().y]; - int samplesX = fullRegion.size().x / sampleRate + 1; - int samplesY = fullRegion.size().y / sampleRate + 1; - for (int y = 0; y < samplesY - 1; y++) { - for (int x = 0; x < samplesX - 1; x++) { - float q11 = keyData[x + y * samplesX]; - float q21 = keyData[x + 1 + y * samplesX]; - float q12 = keyData[x + (y + 1) * samplesX]; - float q22 = keyData[(x + 1) + (y + 1) * samplesX]; - for (int innerY = 0; innerY < sampleRate; ++innerY) { - for (int innerX = 0; innerX < sampleRate; ++innerX) { - fullData[x * sampleRate + innerX + fullRegion.size().x * (y * sampleRate + innerY)] = - TeraMath.biLerp(q11, q21, q12, q22, (float) innerX / sampleRate, (float) innerY / sampleRate); - } - } - } - } - return fullData; - } - - private float[] getKeyValues(Rect2i fullRegion) { - int xDim = fullRegion.size().x / sampleRate + 1; - int yDim = fullRegion.size().y / sampleRate + 1; - float[] fullData = new float[xDim * yDim]; - for (int y = 0; y < yDim; y++) { - for (int x = 0; x < xDim; x++) { - int actualX = x * sampleRate + fullRegion.minX(); - int actualY = y * sampleRate + fullRegion.minY(); - fullData[x + y * xDim] = source.noise(zoom.x * actualX, zoom.y * actualY); - } - } - return fullData; - } - - private Rect2i determineRequiredRegion(Rect2i region) { - int newMinX = region.minX() - IntMath.mod(region.minX(), sampleRate); - int newMinY = region.minY() - IntMath.mod(region.minY(), sampleRate); - int newMaxX = region.maxX() + 4 - IntMath.mod(region.maxX(), sampleRate) - 1; - int newMaxY = region.maxY() + 4 - IntMath.mod(region.maxY(), sampleRate) - 1; - return Rect2i.createFromMinAndMax(newMinX, newMinY, newMaxX, newMaxY); - } -} diff --git a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise3D.java b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise3D.java deleted file mode 100644 index b1eed5ceea6..00000000000 --- a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise3D.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.utilities.procedural; - -import com.google.common.math.IntMath; -import org.terasology.math.Region3i; -import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; - -/** - * @deprecated Use {@link SubSampledNoise} instead - */ -@Deprecated -public class SubSampledNoise3D implements Noise3D { - - private Noise3D source; - private Vector3f zoom = new Vector3f(1, 1, 1); - private int sampleRate = 1; - - public SubSampledNoise3D(Noise3D source, Vector3f zoom, int sampleRate) { - this.source = source; - this.zoom.set(zoom); - this.sampleRate = sampleRate; - } - - @Override - public float noise(float x, float y, float z) { - float xMod = TeraMath.modulus(x, sampleRate); - float yMod = TeraMath.modulus(y, sampleRate); - float zMod = TeraMath.modulus(z, sampleRate); - - float x0 = x - xMod; - float x1 = x0 + sampleRate; - float y0 = y - yMod; - float y1 = y0 + sampleRate; - float z0 = z - zMod; - float z1 = z0 + sampleRate; - - float q000 = source.noise(x0 * zoom.x, y0 * zoom.y, z0 * zoom.z); - float q100 = source.noise(x1 * zoom.x, y0 * zoom.y, z0 * zoom.z); - float q010 = source.noise(x0 * zoom.x, y1 * zoom.y, z0 * zoom.z); - float q110 = source.noise(x1 * zoom.x, y1 * zoom.y, z0 * zoom.z); - float q001 = source.noise(x0 * zoom.x, y0 * zoom.y, z1 * zoom.z); - float q101 = source.noise(x1 * zoom.x, y0 * zoom.y, z1 * zoom.z); - float q011 = source.noise(x0 * zoom.x, y1 * zoom.y, z1 * zoom.z); - float q111 = source.noise(x1 * zoom.x, y1 * zoom.y, z1 * zoom.z); - - return TeraMath.triLerp(q000, q100, q010, q110, q001, q101, q011, q111, xMod / sampleRate, yMod / sampleRate, zMod / sampleRate); - } - - public float[] noise(Region3i region) { - Region3i fullRegion = determineRequiredRegion(region); - float[] keyData = getKeyValues(fullRegion); - float[] fullData = mapExpand(keyData, fullRegion); - return getSubset(fullData, fullRegion, region); - } - - private float[] getSubset(float[] fullData, Region3i fullRegion, Region3i subRegion) { - if (subRegion.size().x != fullRegion.size().x || subRegion.size().y != fullRegion.size().y || subRegion.size().z != fullRegion.size().z) { - float[] result = new float[subRegion.size().x * subRegion.size().y * subRegion.size().z]; - Vector3i offset = new Vector3i(subRegion.minX() - fullRegion.minX(), subRegion.minY() - fullRegion.minY(), subRegion.minZ() - fullRegion.minZ()); - for (int z = 0; z < subRegion.size().z; ++z) { - for (int y = 0; y < subRegion.size().y; ++y) { - System.arraycopy(fullData, offset.x + fullRegion.sizeX() * (y + offset.y + fullRegion.sizeY() * (z + offset.z)), - result, subRegion.sizeX() * (y + subRegion.sizeY() * z), subRegion.size().x); - } - } - return result; - } else { - return fullData; - } - } - - private float[] mapExpand(float[] keyData, Region3i fullRegion) { - float[] fullData = new float[fullRegion.size().x * fullRegion.size().y * fullRegion.size().z]; - int samplesX = fullRegion.size().x / sampleRate + 1; - int samplesY = fullRegion.size().y / sampleRate + 1; - int samplesZ = fullRegion.size().z / sampleRate + 1; - for (int z = 0; z < samplesZ - 1; z++) { - for (int y = 0; y < samplesY - 1; y++) { - for (int x = 0; x < samplesX - 1; x++) { - float q000 = keyData[x + samplesX * (y + samplesY * z)]; - float q100 = keyData[x + 1 + samplesX * (y + samplesY * z)]; - float q010 = keyData[x + samplesX * (y + 1 + samplesY * z)]; - float q110 = keyData[(x + 1) + samplesX * (y + 1 + samplesY * z)]; - float q001 = keyData[x + samplesX * (y + samplesY * (z + 1))]; - float q101 = keyData[x + 1 + samplesX * (y + samplesY * (z + 1))]; - float q011 = keyData[x + samplesX * (y + 1 + samplesY * (z + 1))]; - float q111 = keyData[(x + 1) + samplesX * (y + 1 + samplesY * (z + 1))]; - for (int innerZ = 0; innerZ < sampleRate; ++innerZ) { - for (int innerY = 0; innerY < sampleRate; ++innerY) { - for (int innerX = 0; innerX < sampleRate; ++innerX) { - fullData[x * sampleRate + innerX + fullRegion.sizeX() * (y * sampleRate + innerY + fullRegion.sizeY() * (z * sampleRate + innerZ))] = - TeraMath.triLerp(q000, q100, q010, q110, q001, q101, q011, q111, - (float) innerX / sampleRate, (float) innerY / sampleRate, (float) innerZ / sampleRate); - } - } - } - } - } - } - return fullData; - } - - private float[] getKeyValues(Region3i fullRegion) { - int xDim = fullRegion.size().x / sampleRate + 1; - int yDim = fullRegion.size().y / sampleRate + 1; - int zDim = fullRegion.size().z / sampleRate + 1; - float[] fullData = new float[xDim * yDim * zDim]; - for (int z = 0; z < zDim; z++) { - for (int y = 0; y < yDim; y++) { - for (int x = 0; x < xDim; x++) { - int actualX = x * sampleRate + fullRegion.minX(); - int actualY = y * sampleRate + fullRegion.minY(); - int actualZ = z * sampleRate + fullRegion.minZ(); - fullData[x + xDim * (y + yDim * z)] = source.noise(zoom.x * actualX, zoom.y * actualY, zoom.z * actualZ); - } - } - } - return fullData; - } - - private Region3i determineRequiredRegion(Region3i region) { - int newMinX = region.minX() - IntMath.mod(region.minX(), sampleRate); - int newMinY = region.minY() - IntMath.mod(region.minY(), sampleRate); - int newMinZ = region.minZ() - IntMath.mod(region.minZ(), sampleRate); - int newMaxX = region.maxX() + 4 - IntMath.mod(region.maxX(), sampleRate) - 1; - int newMaxY = region.maxY() + 4 - IntMath.mod(region.maxY(), sampleRate) - 1; - int newMaxZ = region.maxZ() + 4 - IntMath.mod(region.maxZ(), sampleRate) - 1; - return Region3i.createFromMinMax(new Vector3i(newMinX, newMinY, newMinZ), new Vector3i(newMaxX, newMaxY, newMaxZ)); - } -} From 99ba7366d6d40aecfa1b0dfc6f6e1cca18914fde Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:25:57 -0800 Subject: [PATCH 053/259] chore (build): remove unused distModules task --- build.gradle | 14 -------------- facades/PC/build.gradle.kts | 17 ----------------- 2 files changed, 31 deletions(-) diff --git a/build.gradle b/build.gradle index c986c48c023..2538175a7d8 100644 --- a/build.gradle +++ b/build.gradle @@ -184,20 +184,6 @@ task extractConfig(type: Copy) { into "$rootDir/$dirConfigMetrics" } -// Helper that returns a list of all local Terasology module projects -def terasologyModules() { - subprojects.findAll { it.parent.name == 'modules' } -} - -// Helpers that do magic things after having dependencies attached below -task moduleJars - -// This magically makes everything work - without this the desired module projects returned have no tasks :-( -gradle.projectsEvaluated { - // This makes it work for a full jar task - moduleJars.dependsOn(terasologyModules().jar) -} - // Include deletion of extracted natives in the global clean task. Without the doLast it runs on *every* execution ... clean.doLast { new File(dirNatives).deleteDir() diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index c7c9580e3e8..20e16ee72a3 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -264,26 +264,9 @@ tasks.register("distApp") { } } -// Distribute modules - only grabs Core in Jenkins but locally will grab any present. "Distros" now handle Jenkins packs -tasks.register("distModules") { - description = "Prepares local modules for distribution" - dependsOn("distApp") - dependsOn(":moduleJars") - - // So this is probably a hack, but it works ;-) It does not work if it is in distApp, default "into" quirk ? - into("${distsDirectory.get().asFile}/app/modules") - // FIXME: duplicating code from /build.gradle:terasologyModules - val terasologyModules = rootProject.subprojects.filter { it.parent?.name == "modules" } - terasologyModules.forEach { - from("$rootDir/modules/${it.name}/build/libs") - include("*.jar") - } -} - tasks.register("distPCZip") { group = "terasology dist" dependsOn("distApp") - dependsOn("distModules") from("${distsDirectory.get().asFile}/app") archiveFileName.set("Terasology.zip") } From cec2bf519aedb684c7abbce7fd4a646f3686e583 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:31:13 -0800 Subject: [PATCH 054/259] chore (build): remove RemoteModuleGatherer gradle is smart enough to put runtime dependencies on the classpath --- build.gradle | 65 ---------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/build.gradle b/build.gradle index 2538175a7d8..9065dbeb60d 100644 --- a/build.gradle +++ b/build.gradle @@ -226,71 +226,6 @@ project(":modules").subprojects.forEach { proj -> } } -/** - * Gathering remote modules files from remoteRepo to 'modules' for autoloading in game-time (tasks server, game etc) - */ -class RemoteModuleGatherer implements DependencyResolutionListener { - - private final Path modulesDir - private final Logger logger - - RemoteModuleGatherer(Path modulesDir) { - this.modulesDir = modulesDir - this.logger = Logging.getLogger(this.class) - } - - @Override - void beforeResolve(ResolvableDependencies dependencies) { - // nothing to do - } - - @Override - void afterResolve(ResolvableDependencies dependencies) { - // We process only module dependencies - if (dependencies.path.startsWith(":modules:") && - dependencies.name == "compileClasspath") { - def projectName = dependencies.path.split(":")[2] - - if (!dependencies.artifacts.artifacts.empty) { - logger.debug("\nProcessing module '{}' in a multi-project workspace", projectName) - } - - dependencies.artifacts.artifacts.each { - if (isRemoteTerasologyModule(it)) { - println "$projectName resolved binary $it" - def binaryModulePath = modulesDir.resolve(it.file.name) - Files.copy(it.file.toPath(), binaryModulePath, StandardCopyOption.REPLACE_EXISTING) - } else if (isLocalTerasologyModule(it)) { - logger.info("*** Found module dependency {} in source form, not copying a runtime jar from Gradle", it) - } else { - //ignore non terasology module - } - } - } - } - - private static boolean isRemoteTerasologyModule(ResolvedArtifactResult artifact) { - def componentIdentifier = artifact.id.componentIdentifier - if (componentIdentifier instanceof ModuleComponentIdentifier) { - def module = componentIdentifier as ModuleComponentIdentifier - return module.group == 'org.terasology.modules' - } - return false - } - - private static boolean isLocalTerasologyModule(ResolvedArtifactResult artifact) { - def componentIdentifier = artifact.id.componentIdentifier - if (componentIdentifier instanceof ProjectComponentIdentifier) { - def module = componentIdentifier as ProjectComponentIdentifier - return !(module.projectName in ['engine', 'engine-tests']) - } - return false - } -} - -gradle.addListener(new RemoteModuleGatherer(rootDir.toPath().resolve("modules"))) - - tasks.named('wrapper') { // ALL distributionType because IntelliJ prefers having its sources for analysis and reference. distributionType = Wrapper.DistributionType.ALL From 5bac6606b32945ec866febb599d78b1c7478dcc4 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:35:08 -0800 Subject: [PATCH 055/259] chore (build): remove unnecessary IdeaModel overrides When we have resources for gestalt's asset loader we need to be particular about output directories. But the facade does not register gestalt assets itself. We avoid some gradle/intellij build state collisions by not forcing these values. --- facades/PC/build.gradle.kts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 20e16ee72a3..c820db6fc76 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -5,7 +5,6 @@ import org.apache.tools.ant.filters.FixCrLfFilter import org.apache.tools.ant.taskdefs.condition.Os -import org.gradle.plugins.ide.idea.model.IdeaModel import java.text.SimpleDateFormat import java.util.* @@ -72,12 +71,6 @@ application { mainClass.set(extra.get("mainClassName") as String) } -// Adjust as the Gradle 6 upgrade changed this path a bit -sourceSets { - main { java.outputDir = File("$buildDir/classes") } - test { java.outputDir = File("$buildDir/testClasses") } -} - // Base the engine tests on the same version number as the engine version = project(":engine").version logger.info("PC VERSION: {}", version) @@ -284,16 +277,6 @@ tasks.register("distForLauncher") { } } -// Prep an IntelliJ module for the facade -configure { - module { - // Change around the output a bit - inheritOutputDirs = false - outputDir = file("build/classes") - testOutputDir = file("build/testClasses") - } -} - tasks.register("copyEclipseLauncher") { from("$rootDir/config/eclipse") into(projectDir) From d3a6b1a028d8828503f538321160fdea09c9289d Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 12:12:12 -0800 Subject: [PATCH 056/259] chore (build): The PC facade gets to be named "Terasology" --- facades/PC/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index c820db6fc76..235f338422d 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -68,6 +68,7 @@ val displayVersion = versionBase application { + applicationName = "Terasology" mainClass.set(extra.get("mainClassName") as String) } From 79bacf3fa4104907f3aee2e40d1a77ed83597b91 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 13:14:24 -0800 Subject: [PATCH 057/259] chore(build): add README, LICENSE, NOTICE, and VERSION files to the main distribution --- facades/PC/build.gradle.kts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 235f338422d..7989073a449 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -192,11 +192,11 @@ tasks.register("server") { } // Preps a version file to bundle with PC dists. This eventually goes into the root of a zip file -tasks.register("createVersionFile") { +val createVersionFile = tasks.register("createVersionFile") { inputs.property("dateTime", startDateTimeString) onlyIf { env["BUILD_URL"] != null } from(templatesDir) - into("$buildDir") + into("$buildDir/versionfile") include(versionFileName) expand(mapOf( "buildNumber" to env["BUILD_NUMBER"], @@ -209,7 +209,7 @@ tasks.register("createVersionFile") { } // TODO: This could probably be done more Gradley (engine project resource dir instead of direct path?) and with some variables -tasks.register("copyCreditsFile") { +val copyCreditsFile = tasks.register("copyCreditsFile") { description = "Copies the credits file into the engine's resource dir where it'll be read at runtime" from("$rootDir/docs") into("$rootDir/engine/src/main/resources") @@ -278,6 +278,22 @@ tasks.register("distForLauncher") { } } +// TODO: add versionInfo.properties as resource +// TODO: add Credits.md as resource + +distributions { + main { + contents { + from(rootDir) { + include("README.markdown", "LICENSE", "NOTICE") + rename("README.markdown", "README") + filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) + } + from(createVersionFile) + } + } +} + tasks.register("copyEclipseLauncher") { from("$rootDir/config/eclipse") into(projectDir) From 87eb506545043ac0ef2c0864254e6bb555ca3093 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 15:03:38 -0800 Subject: [PATCH 058/259] chore(build): refactor createVersionInfoFile to use specific gradle task type --- engine/build.gradle | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index a0435a4e256..2f3549a1e16 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -216,24 +216,22 @@ group = 'org.terasology.engine' println "Version for $project.name loaded as $version for group $group" // This version info file actually goes inside the built jar and can be used at runtime -task createVersionInfoFile { +def createVersionInfoFile = tasks.register("createVersionInfoFile", WriteProperties) { inputs.property('dateTime', startDateTimeString) - onlyIf { env.BUILD_URL != null } - doLast { - versionInfoFileDir.mkdirs() - ant.propertyfile(file: versionInfoFile) { - ant.entry(key: 'buildNumber', value: env.BUILD_NUMBER) - ant.entry(key: 'buildId', value: env.BUILD_ID) - ant.entry(key: 'buildTag', value: env.BUILD_TAG) - ant.entry(key: 'buildUrl', value: env.BUILD_URL) - ant.entry(key: 'jobName', value: env.JOB_NAME) - ant.entry(key: 'gitBranch', value: convertGitBranch(env.GIT_BRANCH)) - ant.entry(key: 'gitCommit', value: env.GIT_COMMIT) - ant.entry(key: 'dateTime', value: startDateTimeString) - ant.entry(key: 'displayVersion', value: displayVersion) - ant.entry(key: 'engineVersion', value: version) - } - } + //noinspection GroovyAssignabilityCheck + properties([ + buildNumber: env.BUILD_NUMBER, + buildId: env.BUILD_ID, + buildTag: env.BUILD_TAG, + buildUrl: env.BUILD_URL, + jobName: env.JOB_NAME, + gitBranch: convertGitBranch(env.GIT_BRANCH), + gitCommit: env.GIT_COMMIT, + dateTime: startDateTimeString, + displayVersion: displayVersion, + engineVersion: version + ].findAll { it.value != null }) + outputFile = versionInfoFile } From 007cc7459a10144420a6c42b931ce4804c2e69ea Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 16:18:35 -0800 Subject: [PATCH 059/259] chore (build): pass createVersionInfoFile to processResources instead of writing to the build state directly. This helps gradle be consistent about which tasks are responsible for which outputs. --- engine/build.gradle | 11 ++++++----- facades/PC/build.gradle.kts | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index 2f3549a1e16..210c6897eb4 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -29,8 +29,6 @@ ext { // Stuff for our automatic version file setup startDateTimeString = dateTimeFormat.format(new Date()) - versionInfoFileDir = new File(buildDir, 'classes/org/terasology/version') - versionInfoFile = new File(versionInfoFileDir, 'versionInfo.properties') versionFileName = 'VERSION' versionBase = new File(templatesDir, "version.txt").text.trim() displayVersion = versionBase @@ -217,7 +215,6 @@ println "Version for $project.name loaded as $version for group $group" // This version info file actually goes inside the built jar and can be used at runtime def createVersionInfoFile = tasks.register("createVersionInfoFile", WriteProperties) { - inputs.property('dateTime', startDateTimeString) //noinspection GroovyAssignabilityCheck properties([ buildNumber: env.BUILD_NUMBER, @@ -231,9 +228,14 @@ def createVersionInfoFile = tasks.register("createVersionInfoFile", WritePropert displayVersion: displayVersion, engineVersion: version ].findAll { it.value != null }) - outputFile = versionInfoFile + outputFile = "$buildDir/createVersionInfoFile/versionInfo.properties" } +tasks.named("processResources", Copy) { + from(createVersionInfoFile) { + into("org/terasology/version/") + } +} //TODO: Remove it when gestalt will can to handle ProtectionDomain without classes (Resources) task copyResourcesToClasses(type: Copy) { @@ -245,7 +247,6 @@ task copyResourcesToClasses(type: Copy) { classes.dependsOn copyResourcesToClasses } -jar.dependsOn createVersionInfoFile jar.dependsOn cacheReflections /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 7989073a449..d097662b30e 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -278,7 +278,6 @@ tasks.register("distForLauncher") { } } -// TODO: add versionInfo.properties as resource // TODO: add Credits.md as resource distributions { From b1ff0bbfdfdee1beabf1c85a292c5635655682a6 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 28 Dec 2020 16:41:11 -0800 Subject: [PATCH 060/259] chore (build): add Credits.md as an engine resource in engine's build, not facade's --- engine/build.gradle | 3 +++ facades/PC/build.gradle.kts | 11 ----------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index 210c6897eb4..cff1d79d406 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -235,6 +235,9 @@ tasks.named("processResources", Copy) { from(createVersionInfoFile) { into("org/terasology/version/") } + from("$rootDir/docs") { + include("Credits.md") + } } //TODO: Remove it when gestalt will can to handle ProtectionDomain without classes (Resources) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index d097662b30e..3cc3bd359aa 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -208,21 +208,12 @@ val createVersionFile = tasks.register("createVersionFile") { filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) } -// TODO: This could probably be done more Gradley (engine project resource dir instead of direct path?) and with some variables -val copyCreditsFile = tasks.register("copyCreditsFile") { - description = "Copies the credits file into the engine's resource dir where it'll be read at runtime" - from("$rootDir/docs") - into("$rootDir/engine/src/main/resources") - include("Credits.md") -} - // Main application dist target. Does NOT include any modules. tasks.register("distApp") { description = "Creates an application package for distribution" group = "terasology dist" dependsOn("createVersionFile") - dependsOn("copyCreditsFile") dependsOn(":extractNatives") dependsOn("jar") @@ -278,8 +269,6 @@ tasks.register("distForLauncher") { } } -// TODO: add Credits.md as resource - distributions { main { contents { From ccb8bae9bf852310738e16684d8ec997385b5832 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Tue, 29 Dec 2020 20:19:36 +0000 Subject: [PATCH 061/259] fix: Mark new chunks ready before triggering OnChunkLoaded events. (#4353) --- .../world/chunks/localChunkProvider/LocalChunkProvider.java | 2 +- .../world/chunks/remoteChunkProvider/RemoteChunkProvider.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index af3de36684c..0e35b4f5b02 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -197,6 +197,7 @@ private void processReadyChunk(final Chunk chunk) { return; // TODO move it in pipeline; } chunkCache.put(chunk.getPosition(), chunk); + chunk.markReady(); //TODO, it is not clear if the activate/addedBlocks event logic is correct. //See https://github.com/MovingBlocks/Terasology/issues/3244 ChunkStore store = this.storageManager.loadChunkStore(chunk.getPosition()); @@ -244,7 +245,6 @@ private void processReadyChunk(final Chunk chunk) { worldEntity.send(new OnChunkGenerated(chunk.getPosition())); } worldEntity.send(new OnChunkLoaded(chunk.getPosition())); - chunk.markReady(); } private void generateQueuedEntities(EntityStore store) { diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 3a280979ff3..6a004f5edf3 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -80,13 +80,13 @@ public RemoteChunkProvider(BlockManager blockManager, LocalPlayer localPlayer) { .collect(Collectors.toSet()) )) .addStage(ChunkTaskProvider.create("", chunk -> { - listener.onChunkReady(chunk.getPosition()); - worldEntity.send(new OnChunkLoaded(chunk.getPosition())); Chunk oldChunk = chunkCache.put(chunk.getPosition(), chunk); if (oldChunk != null) { oldChunk.dispose(); } chunk.markReady(); + listener.onChunkReady(chunk.getPosition()); + worldEntity.send(new OnChunkLoaded(chunk.getPosition())); })); ChunkMonitor.fireChunkProviderInitialized(this); From e3cb11c481304cb61378160f93e8ae6024845ea2 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:00:15 -0800 Subject: [PATCH 062/259] chore(gradle): add some section headers I think this is a sign that this file is big enough to split up, but that'll make mess of the code review so we'll do that after. --- facades/PC/build.gradle.kts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 3cc3bd359aa..c4b7c061236 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -108,6 +108,10 @@ configurations { } } +/**************************************** + * Run Targets + */ + // Used for all game configs. fun JavaExec.commonConfigure() { group = "terasology run" @@ -160,6 +164,10 @@ tasks.register("permissiveNatives") { systemProperty("java.library.path", rootProject.file(dirNatives + "/" + nativeSubdirectoryName())) } +/****************************************** + * Headless server + */ + apply(from="server.build.gradle") // TODO: Seems to always be up to date so no modules get copied @@ -191,6 +199,13 @@ tasks.register("server") { args("-headless", "-homedir=$localServerDataPath") } + +/********************************* + * Distribution + * + * See also publish.gradle, included near the top. + */ + // Preps a version file to bundle with PC dists. This eventually goes into the root of a zip file val createVersionFile = tasks.register("createVersionFile") { inputs.property("dateTime", startDateTimeString) @@ -282,6 +297,11 @@ distributions { } } + +/******************************** + * Eclipse Integration + */ + tasks.register("copyEclipseLauncher") { from("$rootDir/config/eclipse") into(projectDir) From 2f17e3ea541017ad42ca0c11503212a12b4bba6b Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 11:04:13 -0800 Subject: [PATCH 063/259] feat(JOML): migrate gltf and rendering (#4289) --- .../assets/animation/MeshAnimationFrame.java | 12 ++--- .../rendering/assets/skeletalmesh/Bone.java | 35 ++++---------- .../assets/skeletalmesh/SkeletalMeshData.java | 33 +++++++------ .../skeletalmesh/SkeletalMeshDataBuilder.java | 11 ++--- .../rendering/gltf/GLTFAnimationFormat.java | 39 +++++++++------- .../rendering/gltf/GLTFCommonFormat.java | 46 ++++++++++++++----- .../rendering/gltf/GLTFMeshFormat.java | 34 +++++--------- .../gltf/GLTFSkeletalMeshFormat.java | 15 +++--- .../deserializers/Matrix4fDeserializer.java | 2 +- ...izer.java => QuaternionfDeserializer.java} | 8 ++-- .../deserializers/Vector3fDeserializer.java | 2 +- .../gltf/model/GLTFInterpolation.java | 24 ++++------ .../rendering/gltf/model/GLTFNode.java | 8 ++-- .../rendering/logic/SkeletonRenderer.java | 18 +++----- .../rendering/opengl/OpenGLSkeletalMesh.java | 11 ++--- 15 files changed, 145 insertions(+), 153 deletions(-) rename engine/src/main/java/org/terasology/rendering/gltf/deserializers/{Quat4fDeserializer.java => QuaternionfDeserializer.java} (79%) diff --git a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationFrame.java b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationFrame.java index 60e21a21b75..e4c84817aef 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationFrame.java +++ b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationFrame.java @@ -17,21 +17,19 @@ package org.terasology.rendering.assets.animation; import com.google.common.collect.Lists; +import org.joml.Quaternionf; +import org.joml.Vector3f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; - -import java.util.Collection; import java.util.List; /** */ public class MeshAnimationFrame { private List bonePositions; - private List boneRotations; + private List boneRotations; private List boneScales; - public MeshAnimationFrame(List bonePositions, List boneRotations, List boneScales) { + public MeshAnimationFrame(List bonePositions, List boneRotations, List boneScales) { this.bonePositions = Lists.newArrayList(bonePositions); this.boneRotations = Lists.newArrayList(boneRotations); this.boneScales = Lists.newArrayList(boneScales); @@ -41,7 +39,7 @@ public Vector3f getPosition(int boneId) { return bonePositions.get(boneId); } - public Quat4f getRotation(int boneId) { + public Quaternionf getRotation(int boneId) { return boneRotations.get(boneId); } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/Bone.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/Bone.java index e8ebba72bb2..d1fb4b39fcb 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/Bone.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/Bone.java @@ -17,10 +17,9 @@ package org.terasology.rendering.assets.skeletalmesh; import com.google.common.collect.Lists; - -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.util.Collection; import java.util.List; @@ -31,7 +30,7 @@ public class Bone { private String name; private int index; private Matrix4f relativeTransform = new Matrix4f(); - private Matrix4f inverseBindMatrix = new Matrix4f(Matrix4f.IDENTITY); + private Matrix4f inverseBindMatrix = new Matrix4f(); private Bone parent; private List children = Lists.newArrayList(); @@ -92,32 +91,16 @@ public Collection getChildren() { public Vector3f getLocalPosition() { Vector3f result = new Vector3f(); - relativeTransform.transformPoint(result); + relativeTransform.transformPosition(result); return result; } - public Quat4f getLocalRotation() { - Vector3f scale = getLocalScale(); - Matrix4f descaled = new Matrix4f(relativeTransform); - descaled.m00 /= scale.x; - descaled.m10 /= scale.x; - descaled.m20 /= scale.x; - descaled.m01 /= scale.y; - descaled.m11 /= scale.y; - descaled.m21 /= scale.y; - descaled.m02 /= scale.z; - descaled.m12 /= scale.z; - descaled.m22 /= scale.z; - Quat4f result = new Quat4f(Quat4f.IDENTITY); - result.set(descaled); - return result; + public Quaternionf getLocalRotation() { + return relativeTransform.getNormalizedRotation(new Quaternionf()); } public Vector3f getLocalScale() { - return new Vector3f( - new Vector3f(relativeTransform.getM00(),relativeTransform.getM10(),relativeTransform.getM20()).length(), - new Vector3f(relativeTransform.getM01(),relativeTransform.getM11(),relativeTransform.getM21()).length(), - new Vector3f(relativeTransform.getM02(),relativeTransform.getM12(),relativeTransform.getM22()).length() - ); + return relativeTransform.getScale(new Vector3f()); + } } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java index dd6ca2e2222..44d398d5f57 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java @@ -20,12 +20,11 @@ import com.google.common.collect.Maps; import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector3f; import org.terasology.assets.AssetData; import org.terasology.math.AABB; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; import java.util.Arrays; import java.util.Collection; @@ -47,7 +46,8 @@ public class SkeletalMeshData implements AssetData { private TIntList indices = new TIntArrayList(); private AABB staticAABB; - public SkeletalMeshData(List bones, List vertices, List normals, List weights, List uvs, TIntList indices, AABB staticAABB) { + public SkeletalMeshData(List bones, List vertices, List normals, + List weights, List uvs, TIntList indices, AABB staticAABB) { for (Bone bone : bones) { boneLookup.put(bone.getName(), bone); if (bone.getParent() == null) { @@ -102,7 +102,9 @@ public List getBindPoseVertexNormals() { } /** - * Provides the positions of all vertices of the mesh, transformed based on the transformation matrices of all bones + * Provides the positions of all vertices of the mesh, transformed based on the transformation matrices of all + * bones + * * @param boneTransforms A transformation matrix for each bone in the skeletal mesh * @return The positions of each vertex */ @@ -110,14 +112,14 @@ public List getVertexPositions(List boneTransforms) { List results = Lists.newArrayListWithCapacity(getVertexCount()); for (int i = 0; i < vertices.size(); i++) { Vector3f pos = new Vector3f(vertices.get(i)); - Matrix4f skinMat = new Matrix4f(); + Matrix4f skinMat = new Matrix4f().m00(0).m11(0).m22(0).m33(0); BoneWeight weight = weights.get(i); for (int w = 0; w < weight.jointCount(); w++) { Matrix4f jointMat = new Matrix4f(boneTransforms.get(weight.getJoint(w))); - jointMat.mul(weight.getBias(w)); + jointMat.scale(weight.getBias(w)); skinMat.add(jointMat); } - skinMat.transformPoint(pos); + pos.mulTransposePosition(skinMat); results.add(pos); } return results; @@ -125,6 +127,7 @@ public List getVertexPositions(List boneTransforms) { /** * Provides the normals of all vertices of the mesh, transformed based on the transformation matrices of all bones + * * @param boneTransforms A transformation matrix for each bone in the skeletal mesh * @return The normals of each vertex */ @@ -132,14 +135,14 @@ public List getVertexNormals(List boneTransforms) { List results = Lists.newArrayListWithCapacity(getVertexCount()); for (int i = 0; i < normals.size(); i++) { Vector3f norm = new Vector3f(normals.get(i)); - Matrix4f skinMat = new Matrix4f(); + Matrix4f skinMat = new Matrix4f().m00(0).m11(0).m22(0).m33(0); BoneWeight weight = weights.get(i); for (int w = 0; w < weight.jointCount(); w++) { Matrix4f jointMat = new Matrix4f(boneTransforms.get(weight.getJoint(w))); - jointMat.mul(weight.getBias(w)); + jointMat.scale(weight.getBias(w)); skinMat.add(jointMat); } - skinMat.transformVector(norm); + norm.mulTransposePosition(skinMat); results.add(norm); } return results; @@ -193,11 +196,11 @@ private void calculateNormals() { Vector3f norm = new Vector3f(); for (int i = 0; i < indices.size() / 3; ++i) { Vector3f baseVert = vertices.get(indices.get(i * 3)); - v1.sub(vertices.get(indices.get(i * 3 + 1)), baseVert); - v2.sub(vertices.get(indices.get(i * 3 + 2)), baseVert); + vertices.get(indices.get(i * 3 + 1)).sub(baseVert, v1); + vertices.get(indices.get(i * 3 + 2)).sub(baseVert, v2); v1.normalize(); v2.normalize(); - norm.cross(v1, v2); + v2.cross(v1, norm); normals.get(indices.get(i * 3)).add(norm); normals.get(indices.get(i * 3 + 1)).add(norm); normals.get(indices.get(i * 3 + 2)).add(norm); diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java index 085e381eb68..6ea1f8809b9 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java @@ -15,14 +15,13 @@ */ package org.terasology.rendering.assets.skeletalmesh; -import com.google.common.collect.Lists; import gnu.trove.list.TFloatList; import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; +import org.joml.Vector2f; +import org.joml.Vector3f; import org.terasology.math.AABB; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; +import org.terasology.math.JomlUtil; import org.terasology.rendering.assets.mesh.MeshBuilder; import org.terasology.rendering.assets.mesh.MeshData; @@ -74,7 +73,7 @@ public SkeletalMeshDataBuilder addMesh(Bone bone, MeshBuilder builder) { public SkeletalMeshDataBuilder addBox(Bone bone, Vector3f offset, Vector3f size, float u, float v) { MeshBuilder meshBuilder = new MeshBuilder(); meshBuilder.setTextureMapper(textureMapper); - meshBuilder.addBox(offset, size, u, v); + meshBuilder.addBox(JomlUtil.from(offset), JomlUtil.from(size), u, v); return addMesh(bone, meshBuilder); } @@ -136,7 +135,7 @@ public SkeletalMeshData build() { } else if (rootBones > 1) { throw new IllegalStateException("Cannot create a skeleton with multiple root bones"); } - AABB staticAabb = AABB.createMinMax(minOfAABB, maxOfAABB); + AABB staticAabb = AABB.createMinMax(JomlUtil.from(minOfAABB), JomlUtil.from(maxOfAABB)); return new SkeletalMeshData(bones, vertices, normals, weights, uvs, indices, staticAabb); } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java b/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java index 1275c8b9483..dd4f6770fae 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java @@ -23,13 +23,13 @@ import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.TIntIntMap; import gnu.trove.map.hash.TIntIntHashMap; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.assets.ResourceUrn; import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; import org.terasology.math.AABB; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.rendering.assets.animation.MeshAnimationBundleData; import org.terasology.rendering.assets.animation.MeshAnimationData; import org.terasology.rendering.assets.animation.MeshAnimationFrame; @@ -97,14 +97,17 @@ public MeshAnimationBundleData load(ResourceUrn urn, List inputs) name = "anim_" + index; } - animations.put(new ResourceUrn(urn, name), loadAnimation(gltf, gltfAnimation, loadedBuffers, nodeToJoint, boneNames, boneParents, bones)); + animations.put(new ResourceUrn(urn, name), loadAnimation(gltf, gltfAnimation, loadedBuffers, + nodeToJoint, boneNames, boneParents, bones)); } return new MeshAnimationBundleData(animations); } } - private MeshAnimationData loadAnimation(GLTF gltf, GLTFAnimation animation, List loadedBuffers, TIntIntMap boneIndexMapping, List boneNames, TIntList boneParents, List bones) throws IOException { + private MeshAnimationData loadAnimation(GLTF gltf, GLTFAnimation animation, List loadedBuffers, + TIntIntMap boneIndexMapping, List boneNames, TIntList boneParents + , List bones) throws IOException { List channelReaders = new ArrayList<>(); for (GLTFChannel channel : animation.getChannels()) { @@ -116,17 +119,20 @@ private MeshAnimationData loadAnimation(GLTF gltf, GLTFAnimation animation, List case TRANSLATION: { List data = getVector3fs(gltf, loadedBuffers, sampler.getOutput()); - channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate, x -> x.getPosition(bone))); + channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate + , x -> x.getPosition(bone))); break; } case ROTATION: { - List data = getQuat4fs(gltf, loadedBuffers, sampler.getOutput()); - channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate, x -> x.getRotation(bone))); + List data = getQuat4fs(gltf, loadedBuffers, sampler.getOutput()); + channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate + , x -> x.getRotation(bone))); break; } case SCALE: { List data = getVector3fs(gltf, loadedBuffers, sampler.getOutput()); - channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate, x -> x.getBoneScale(bone))); + channelReaders.add(new BufferChannelReader<>(times, data, sampler.getInterpolation()::interpolate + , x -> x.getBoneScale(bone))); break; } default: @@ -134,17 +140,18 @@ private MeshAnimationData loadAnimation(GLTF gltf, GLTFAnimation animation, List } } - int frameCount = (int) (channelReaders.stream().map(ChannelReader::endTime).reduce(Float::max).orElse(0f) / TIME_PER_FRAME) + 1; + int frameCount = + (int) (channelReaders.stream().map(ChannelReader::endTime).reduce(Float::max).orElse(0f) / TIME_PER_FRAME) + 1; List frames = new ArrayList<>(frameCount); for (int i = 0; i < frameCount; i++) { float time = i * TIME_PER_FRAME; List boneLocations = new ArrayList<>(); - List boneRotations = new ArrayList<>(); + List boneRotations = new ArrayList<>(); List boneScales = new ArrayList<>(); for (Bone bone : bones) { boneLocations.add(new Vector3f(bone.getLocalPosition())); - boneRotations.add(new Quat4f(bone.getLocalRotation())); + boneRotations.add(new Quaternionf(bone.getLocalRotation())); boneScales.add(new Vector3f(bone.getLocalScale())); } MeshAnimationFrame frame = new MeshAnimationFrame(boneLocations, boneRotations, boneScales); @@ -172,11 +179,11 @@ private List getVector3fs(GLTF gltf, List loadedBuffers, int a return vectors; } - private List getQuat4fs(GLTF gltf, List loadedBuffers, int accessorIndex) throws IOException { + private List getQuat4fs(GLTF gltf, List loadedBuffers, int accessorIndex) throws IOException { TFloatList floats = getFloats(gltf, loadedBuffers, accessorIndex); - List quats = Lists.newArrayListWithCapacity(floats.size() / 4); + List quats = Lists.newArrayListWithCapacity(floats.size() / 4); for (int i = 0; i < floats.size(); i += 4) { - quats.add(new Quat4f(floats.get(i), floats.get(i + 1), floats.get(i + 2), floats.get(i + 3))); + quats.add(new Quaternionf(floats.get(i), floats.get(i + 1), floats.get(i + 2), floats.get(i + 3))); } return quats; } @@ -202,7 +209,8 @@ private class BufferChannelReader implements ChannelReader { private Interpolator interpolator; private TargetRetriever targetRetriever; - BufferChannelReader(TFloatList times, List data, Interpolator interpolator, TargetRetriever targetRetriever) { + BufferChannelReader(TFloatList times, List data, Interpolator interpolator, + TargetRetriever targetRetriever) { this.times = times; this.data = data; this.interpolator = interpolator; @@ -228,5 +236,4 @@ public float endTime() { return times.get(times.size() - 1); } } - } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/GLTFCommonFormat.java b/engine/src/main/java/org/terasology/rendering/gltf/GLTFCommonFormat.java index 58fbb216c6d..bf057a5de12 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/GLTFCommonFormat.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/GLTFCommonFormat.java @@ -27,9 +27,12 @@ import gnu.trove.list.array.TFloatArrayList; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.TIntIntMap; -import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntIntHashMap; -import gnu.trove.map.hash.TIntObjectHashMap; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector4f; import org.joml.Vector4i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,11 +40,31 @@ import org.terasology.assets.ResourceUrn; import org.terasology.assets.format.AbstractAssetFileFormat; import org.terasology.assets.management.AssetManager; -import org.terasology.math.MatrixUtils; -import org.terasology.math.geom.*; -import org.terasology.rendering.gltf.deserializers.*; -import org.terasology.rendering.gltf.model.*; import org.terasology.rendering.assets.skeletalmesh.Bone; +import org.terasology.rendering.gltf.deserializers.GLTFChannelPathDeserializer; +import org.terasology.rendering.gltf.deserializers.GLTFComponentTypeDeserializer; +import org.terasology.rendering.gltf.deserializers.GLTFModeDeserializer; +import org.terasology.rendering.gltf.deserializers.GLTFTargetBufferDeserializer; +import org.terasology.rendering.gltf.deserializers.GLTFVersionDeserializer; +import org.terasology.rendering.gltf.deserializers.Matrix4fDeserializer; +import org.terasology.rendering.gltf.deserializers.QuaternionfDeserializer; +import org.terasology.rendering.gltf.deserializers.TFloatListDeserializer; +import org.terasology.rendering.gltf.deserializers.TIntListDeserializer; +import org.terasology.rendering.gltf.deserializers.Vector3fDeserializer; +import org.terasology.rendering.gltf.model.GLTF; +import org.terasology.rendering.gltf.model.GLTFAccessor; +import org.terasology.rendering.gltf.model.GLTFAttributeType; +import org.terasology.rendering.gltf.model.GLTFBuffer; +import org.terasology.rendering.gltf.model.GLTFBufferView; +import org.terasology.rendering.gltf.model.GLTFChannelPath; +import org.terasology.rendering.gltf.model.GLTFComponentType; +import org.terasology.rendering.gltf.model.GLTFMesh; +import org.terasology.rendering.gltf.model.GLTFMode; +import org.terasology.rendering.gltf.model.GLTFNode; +import org.terasology.rendering.gltf.model.GLTFPrimitive; +import org.terasology.rendering.gltf.model.GLTFSkin; +import org.terasology.rendering.gltf.model.GLTFTargetBuffer; +import org.terasology.rendering.gltf.model.GLTFVersion; import java.io.IOException; import java.nio.ByteBuffer; @@ -65,7 +88,7 @@ public abstract class GLTFCommonFormat extends AbstractAsse .registerTypeAdapter(TIntList.class, new TIntListDeserializer()) .registerTypeAdapter(TFloatList.class, new TFloatListDeserializer()) .registerTypeAdapter(Matrix4f.class, new Matrix4fDeserializer()) - .registerTypeAdapter(Quat4f.class, new Quat4fDeserializer()) + .registerTypeAdapter(Quaternionf.class, new QuaternionfDeserializer()) .registerTypeAdapter(Vector3f.class, new Vector3fDeserializer()) .registerTypeAdapter(GLTFComponentType.class, new GLTFComponentTypeDeserializer()) .registerTypeAdapter(GLTFMode.class, new GLTFModeDeserializer()) @@ -234,8 +257,8 @@ protected List loadBones(GLTF gltf, GLTFSkin skin, List loadedBuff int nodeIndex = skin.getJoints().get(i); GLTFNode node = gltf.getNodes().get(nodeIndex); Vector3f position = new Vector3f(); - Quat4f rotation = new Quat4f(Quat4f.IDENTITY); - Vector3f scale = new Vector3f(Vector3f.one()); + Quaternionf rotation = new Quaternionf(); + Vector3f scale = new Vector3f(1,1,1); if (node.getTranslation() != null) { position.set(node.getTranslation()); } @@ -249,7 +272,7 @@ protected List loadBones(GLTF gltf, GLTFSkin skin, List loadedBuff if (Strings.isNullOrEmpty(boneName)) { boneName = "bone_" + i; } - Bone bone = new Bone(i, boneName, new Matrix4f(rotation, position, scale.x)); + Bone bone = new Bone(i, boneName, new Matrix4f().translationRotateScale(position, rotation, scale)); bone.setInverseBindMatrix(inverseMats.get(i)); bones.add(bone); boneToJoint.put(nodeIndex, i); @@ -273,7 +296,7 @@ public List loadInverseMats(Integer inverseBindMatrices, int size, GLT } else { result = new ArrayList<>(size); for (int i = 0; i < size; i++) { - result.add(new Matrix4f(Matrix4f.IDENTITY)); + result.add(new Matrix4f()); } } return result; @@ -293,7 +316,6 @@ protected List loadMat4fList(int inverseBindMatrices, GLTF gltf, List< values.get(i + 8), values.get(i + 9), values.get(i + 10), values.get(i + 11), values.get(i + 12), values.get(i + 13), values.get(i + 14), values.get(i + 15) ); - mat.transpose(); matricies.add(mat); } return matricies; diff --git a/engine/src/main/java/org/terasology/rendering/gltf/GLTFMeshFormat.java b/engine/src/main/java/org/terasology/rendering/gltf/GLTFMeshFormat.java index dddab627871..dbe1fa1cc88 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/GLTFMeshFormat.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/GLTFMeshFormat.java @@ -16,15 +16,15 @@ package org.terasology.rendering.gltf; import gnu.trove.list.TFloatList; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.rendering.assets.mesh.MeshData; import org.terasology.rendering.gltf.model.GLTF; import org.terasology.rendering.gltf.model.GLTFAccessor; @@ -113,14 +113,14 @@ private void applyTransformations(GLTF gltf, TFloatList vertices, TFloatList nor } private Matrix4f getMatrix(GLTF gltf, int nodeIndex) { - Matrix4f transform = new Matrix4f(Matrix4f.IDENTITY); + Matrix4f transform = new Matrix4f(); if (nodeIndex != -1) { GLTFNode node = gltf.getNodes().get(nodeIndex); if (node.getMatrix() == null) { Vector3f position = new Vector3f(); - Quat4f rotation = new Quat4f(Quat4f.IDENTITY); - Vector3f scale = new Vector3f(Vector3f.one()); + Quaternionf rotation = new Quaternionf(); + Vector3f scale = new Vector3f(1, 1, 1); if (node.getTranslation() != null) { position.set(node.getTranslation()); @@ -131,19 +131,7 @@ private Matrix4f getMatrix(GLTF gltf, int nodeIndex) { if (node.getScale() != null) { scale.set(node.getScale()); } - transform.set(new Matrix4f(rotation, position, 1.0f)); - - transform.set(0, 0, scale.getX() * transform.get(0, 0)); - transform.set(0, 1, scale.getX() * transform.get(0, 1)); - transform.set(0, 2, scale.getX() * transform.get(0, 2)); - - transform.set(1, 0, scale.getY() * transform.get(1, 0)); - transform.set(1, 1, scale.getY() * transform.get(1, 1)); - transform.set(1, 2, scale.getY() * transform.get(1, 2)); - - transform.set(2, 0, scale.getZ() * transform.get(2, 0)); - transform.set(2, 1, scale.getZ() * transform.get(2, 1)); - transform.set(2, 2, scale.getZ() * transform.get(2, 2)); + transform.translationRotateScale(position, rotation, scale); } else { transform.set(node.getMatrix()); } @@ -171,13 +159,13 @@ private void applyTransformations(TFloatList buffer, Matrix4f transform, boolean Vector3f current = new Vector3f(); for (int i = 0; i < buffer.size(); i += 3) { current.set(buffer.get(i), buffer.get(i + 1), buffer.get(i + 2)); - transform.transformPoint(current); + transform.transformPosition(current); if (normalize) { current.normalize(); } - buffer.set(i, current.getX()); - buffer.set(i + 1, current.getY()); - buffer.set(i + 2, current.getZ()); + buffer.set(i, current.x()); + buffer.set(i + 1, current.y()); + buffer.set(i + 2, current.z()); } } } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/GLTFSkeletalMeshFormat.java b/engine/src/main/java/org/terasology/rendering/gltf/GLTFSkeletalMeshFormat.java index 38c3ba12784..a9716a79238 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/GLTFSkeletalMeshFormat.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/GLTFSkeletalMeshFormat.java @@ -15,28 +15,27 @@ */ package org.terasology.rendering.gltf; -import com.google.common.collect.Lists; -import gnu.trove.iterator.TIntObjectIterator; import gnu.trove.list.TFloatList; import gnu.trove.list.TIntList; import gnu.trove.list.array.TFloatArrayList; import gnu.trove.list.array.TIntArrayList; -import gnu.trove.map.TIntIntMap; -import gnu.trove.map.TIntObjectMap; -import gnu.trove.map.hash.TIntIntHashMap; -import org.joml.Vector4i; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; -import org.terasology.math.geom.*; -import org.terasology.rendering.gltf.model.*; import org.terasology.rendering.assets.skeletalmesh.Bone; import org.terasology.rendering.assets.skeletalmesh.BoneWeight; import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshData; import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshDataBuilder; +import org.terasology.rendering.gltf.model.GLTF; +import org.terasology.rendering.gltf.model.GLTFAccessor; +import org.terasology.rendering.gltf.model.GLTFBufferView; +import org.terasology.rendering.gltf.model.GLTFMesh; +import org.terasology.rendering.gltf.model.GLTFPrimitive; +import org.terasology.rendering.gltf.model.GLTFSkin; import java.io.IOException; import java.io.InputStreamReader; diff --git a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Matrix4fDeserializer.java b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Matrix4fDeserializer.java index 663083b3fb5..8ce76fc4d89 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Matrix4fDeserializer.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Matrix4fDeserializer.java @@ -21,7 +21,7 @@ import com.google.gson.JsonParseException; import gnu.trove.list.TFloatList; import gnu.trove.list.array.TFloatArrayList; -import org.terasology.math.geom.Matrix4f; +import org.joml.Matrix4f; import java.lang.reflect.Type; diff --git a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Quat4fDeserializer.java b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/QuaternionfDeserializer.java similarity index 79% rename from engine/src/main/java/org/terasology/rendering/gltf/deserializers/Quat4fDeserializer.java rename to engine/src/main/java/org/terasology/rendering/gltf/deserializers/QuaternionfDeserializer.java index e2d9a7eebef..2dee03f404a 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Quat4fDeserializer.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/QuaternionfDeserializer.java @@ -21,21 +21,21 @@ import com.google.gson.JsonParseException; import gnu.trove.list.TFloatList; import gnu.trove.list.array.TFloatArrayList; -import org.terasology.math.geom.Quat4f; +import org.joml.Quaternionf; import java.lang.reflect.Type; /** * Json deserializer for an Quat4f. */ -public class Quat4fDeserializer implements JsonDeserializer { +public class QuaternionfDeserializer implements JsonDeserializer { @Override - public Quat4f deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public Quaternionf deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { TFloatList result = new TFloatArrayList(); json.getAsJsonArray().forEach(x -> result.add(x.getAsFloat())); if (result.size() != 4) { throw new JsonParseException("Incorrect number of values for ImmutableQuat4f - expected 4"); } - return new Quat4f(result.get(0), result.get(1), result.get(2), result.get(3)); + return new Quaternionf(result.get(0), result.get(1), result.get(2), result.get(3)); } } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Vector3fDeserializer.java b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Vector3fDeserializer.java index 839af0bd3b7..7bd736d5d6a 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Vector3fDeserializer.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/deserializers/Vector3fDeserializer.java @@ -21,7 +21,7 @@ import com.google.gson.JsonParseException; import gnu.trove.list.TFloatList; import gnu.trove.list.array.TFloatArrayList; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; import java.lang.reflect.Type; diff --git a/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFInterpolation.java b/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFInterpolation.java index be9824bf3c7..ab7ed1504c2 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFInterpolation.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFInterpolation.java @@ -15,30 +15,26 @@ */ package org.terasology.rendering.gltf.model; -import org.terasology.math.geom.BaseQuat4f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; + +import org.joml.Quaternionf; +import org.joml.Vector3f; /** * Animation Interpolation algorithms */ public enum GLTFInterpolation { /** - * For initial value 'a' and next value 'b' and delta time 't' - * a + (b - a ) * t + * For initial value 'a' and next value 'b' and delta time 't' a + (b - a ) * t */ LINEAR { @Override public void interpolate(Vector3f a, Vector3f b, float t, Vector3f out) { - out.x = a.x + t * (b.x - a.x); - out.y = a.y + t * (b.y - a.y); - out.z = a.z + t * (b.z - a.z); - + a.lerp(b, t, out); } @Override - public void interpolate(Quat4f a, Quat4f b, float t, Quat4f out) { - out.set(BaseQuat4f.interpolate(a, b, t)); + public void interpolate(Quaternionf a, Quaternionf b, float t, Quaternionf out) { + a.slerp(b, t, out); } }, /** @@ -51,7 +47,7 @@ public void interpolate(Vector3f a, Vector3f b, float t, Vector3f out) { } @Override - public void interpolate(Quat4f a, Quat4f b, float t, Quat4f out) { + public void interpolate(Quaternionf a, Quaternionf b, float t, Quaternionf out) { out.set(a); } }, @@ -65,7 +61,7 @@ public void interpolate(Vector3f a, Vector3f b, float t, Vector3f out) { } @Override - public void interpolate(Quat4f a, Quat4f b, float t, Quat4f out) { + public void interpolate(Quaternionf a, Quaternionf b, float t, Quaternionf out) { out.set(a); } }; @@ -73,5 +69,5 @@ public void interpolate(Quat4f a, Quat4f b, float t, Quat4f out) { public abstract void interpolate(Vector3f a, Vector3f b, float t, Vector3f out); - public abstract void interpolate(Quat4f a, Quat4f b, float t, Quat4f out); + public abstract void interpolate(Quaternionf a, Quaternionf b, float t, Quaternionf out); } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFNode.java b/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFNode.java index 67690810374..20b53a011ad 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFNode.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/model/GLTFNode.java @@ -17,7 +17,9 @@ import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; -import org.terasology.math.geom.*; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import javax.annotation.Nullable; @@ -33,7 +35,7 @@ public class GLTFNode { private Integer skin; private Matrix4f matrix; private Integer mesh; - private Quat4f rotation; + private Quaternionf rotation; private Vector3f scale; private Vector3f translation; private TIntList weights = new TIntArrayList(); @@ -70,7 +72,7 @@ public Matrix4f getMatrix() { /** * @return The rotation of this node */ - public Quat4f getRotation() { + public Quaternionf getRotation() { return rotation; } diff --git a/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java index 295bb3c34c4..11d48b6ee5d 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java @@ -199,12 +199,12 @@ private void updateSkeleton(SkeletalMeshComponent skeletalMeshComp, MeshAnimatio } LocationComponent boneLoc = boneEntity.getComponent(LocationComponent.class); if (boneLoc != null) { - Vector3f newPos = JomlUtil.from(frameA.getPosition(i)).lerp(JomlUtil.from(frameB.getPosition(i)), interpolationVal, new Vector3f()); + Vector3f newPos = frameA.getPosition(i).lerp(frameB.getPosition(i), interpolationVal, new Vector3f()); boneLoc.setLocalPosition(newPos); - Quaternionf newRot = JomlUtil.from(frameA.getRotation(i)).slerp(JomlUtil.from(frameB.getRotation(i)), interpolationVal, new Quaternionf()); + Quaternionf newRot = frameA.getRotation(i).slerp(frameB.getRotation(i), interpolationVal, new Quaternionf()); newRot.normalize(); boneLoc.setLocalRotation(newRot); - boneLoc.setLocalScale(JomlUtil.from(frameA.getBoneScale(i)).lerp(JomlUtil.from(frameB.getBoneScale(i)), interpolationVal, new Vector3f()).x); + boneLoc.setLocalScale(frameA.getBoneScale(i).lerp(frameB.getBoneScale(i), interpolationVal, new Vector3f()).x); boneEntity.saveComponent(boneLoc); } } @@ -272,7 +272,7 @@ public void renderOpaque() { modelViewMatrix.get(tempMatrixBuffer44); skeletalMesh.material.setMatrix4("worldViewMatrix", tempMatrixBuffer44, true); - modelViewMatrix.get3x3(new Matrix3f()).invert().get(tempMatrixBuffer33); + modelViewMatrix.normal(new Matrix3f()).get(tempMatrixBuffer33); skeletalMesh.material.setMatrix3("normalMatrix", tempMatrixBuffer33, true); skeletalMesh.material.setFloat("sunlight", worldRenderer.getMainLightIntensityAt(JomlUtil.from(worldPos)), true); @@ -288,8 +288,8 @@ public void renderOpaque() { if (boneLocation != null) { Matrix4f boneTransform = new Matrix4f(); boneLocation.getRelativeTransform(boneTransform, entity); - boneTransform.mul(JomlUtil.from(bone.getInverseBindMatrix()).transpose()); - boneTransforms[bone.getIndex()] = boneTransform; + boneTransform.mul(bone.getInverseBindMatrix()); + boneTransforms[bone.getIndex()] = boneTransform.transpose(); } else { logger.warn("Unable to resolve bone \"{}\"", bone.getName()); boneTransforms[bone.getIndex()] = new Matrix4f(); @@ -297,11 +297,7 @@ public void renderOpaque() { } } ((OpenGLSkeletalMesh) skeletalMesh.mesh).setScaleTranslate(skeletalMesh.scale, skeletalMesh.translate); - ((OpenGLSkeletalMesh) skeletalMesh.mesh).render(Arrays.stream(boneTransforms).map(k -> { - org.terasology.math.geom.Matrix4f t = JomlUtil.from(k); - t.transpose(); - return t; - }).collect(Collectors.toList())); + ((OpenGLSkeletalMesh) skeletalMesh.mesh).render(Arrays.asList(boneTransforms)); } } diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java index 57c4bdd846b..fc4a14dbb55 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java @@ -15,6 +15,9 @@ */ package org.terasology.rendering.opengl; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector3f; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; @@ -26,10 +29,6 @@ import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.math.AABB; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.skeletalmesh.Bone; import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; @@ -64,8 +63,8 @@ public class OpenGLSkeletalMesh extends SkeletalMesh { private SkeletalMeshData data; - private org.joml.Vector3f scale; - private org.joml.Vector3f translate; + private Vector3f scale; + private Vector3f translate; private DisposalAction disposalAction; From 13a091b3b223f7f3032f7b85ae37209a3a559865 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 11:40:25 -0800 Subject: [PATCH 064/259] feat(JOML): Chunks Standardization (#4306) Co-authored-by: Tobias Nett --- .../org/terasology/math/ChunkMathTest.java | 103 ++---- .../world/block/BlockRegionTest.java | 18 ++ .../java/org/terasology/math/ChunkMath.java | 10 +- .../terasology/world/block/BlockRegion.java | 14 + .../terasology/world/block/BlockRegionc.java | 32 ++ .../world/chunks/ChunkConstants.java | 4 + .../org/terasology/world/chunks/Chunks.java | 306 ++++++++++++++++++ 7 files changed, 414 insertions(+), 73 deletions(-) create mode 100644 engine/src/main/java/org/terasology/world/chunks/Chunks.java diff --git a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java index 20c732e9a24..7b65c9aa703 100644 --- a/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java +++ b/engine-tests/src/test/java/org/terasology/math/ChunkMathTest.java @@ -15,105 +15,64 @@ */ package org.terasology.math; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.junit.jupiter.api.Test; import org.terasology.config.Config; import org.terasology.context.internal.ContextImpl; import org.terasology.context.internal.MockContext; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.BlockRegion; +import org.terasology.world.chunks.Chunks; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; public class ChunkMathTest { - - @Test - public void testGetEdgeRegion() { - Region3i region = Region3i.createFromMinAndSize(new Vector3i(16, 0, 16), new Vector3i(16, 128, 16)); - assertEquals(Region3i.createFromMinMax(new Vector3i(16, 0, 16), new Vector3i(16, 127, 31)), ChunkMath.getEdgeRegion(region, Side.LEFT)); - } - @Test public void testRegionPositions() { CoreRegistry.setContext(new ContextImpl()); CoreRegistry.put(Config.class, new Config(new MockContext())); - assertEquals(1, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0))).length); - assertEquals(1, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(31, 63, 31))).length); - assertEquals(2, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(32, 63, 31))).length); - assertEquals(4, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(32, 63, 32))).length); - assertEquals(8, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(32, 64, 32))).length); - assertEquals(12, ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(-1, 0, 0), new Vector3i(32, 64, 32))).length); - - Vector3i[] chunks = ChunkMath.calcChunkPos(Region3i.createFromMinMax(new Vector3i(0, 0, 0), new Vector3i(32, 63, 31))); - assertEquals(new Vector3i(0, 0, 0), chunks[0]); - assertEquals(new Vector3i(1, 0, 0), chunks[1]); + assertEquals(new BlockRegion(0, 0, 0, 0, 0, 0), Chunks.toChunkRegion(new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(0, 0, 0)), new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(0, 0, 0, 0, 0, 0), Chunks.toChunkRegion(new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(31, 63, 31)), new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(0, 0, 0, 1, 0, 0), Chunks.toChunkRegion(new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(32, 63, 31)), new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(0, 0, 0, 1, 0, 1), Chunks.toChunkRegion(new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(32, 63, 32)), new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(0, 0, 0, 1, 1, 1), Chunks.toChunkRegion(new BlockRegion(new Vector3i(0, 0, 0), new Vector3i(32, 64, 32)), new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(-1, 0, 0, 1, 1, 1), Chunks.toChunkRegion(new BlockRegion(new Vector3i(-1, 0, 0), new Vector3i(32, 64, 32)), new BlockRegion(BlockRegion.INVALID))); } @Test public void testCalcChunk() { - assertEquals(0, ChunkMath.calcChunkPos(10, 6)); - assertEquals(-1, ChunkMath.calcChunkPos(-1, 6)); - assertEquals(1, ChunkMath.calcChunkPos(100, 6)); - assertEquals(3, ChunkMath.calcChunkPos(200, 6)); - } - - @Test - public void testCalcChunkPosX() { - assertEquals(0, ChunkMath.calcChunkPosX(10)); - assertEquals(-1, ChunkMath.calcChunkPosX(-1)); - assertEquals(3, ChunkMath.calcChunkPosX(100)); - assertEquals(6, ChunkMath.calcChunkPosX(200)); - assertEquals(21, ChunkMath.calcChunkPosX(700)); - } - - @Test - public void testCalcChunkPosY() { - assertEquals(0, ChunkMath.calcChunkPosY(10)); - assertEquals(-1, ChunkMath.calcChunkPosY(-1)); - assertEquals(1, ChunkMath.calcChunkPosY(100)); - assertEquals(3, ChunkMath.calcChunkPosY(200)); - assertEquals(10, ChunkMath.calcChunkPosY(700)); - } - - @Test - public void testCalcChunkPosZ() { - assertEquals(0, ChunkMath.calcChunkPosZ(10)); - assertEquals(-1, ChunkMath.calcChunkPosZ(-1)); - assertEquals(6, ChunkMath.calcChunkPosZ(200)); - assertEquals(21, ChunkMath.calcChunkPosZ(700)); + assertEquals(0, Chunks.toChunkPos(10, 6)); + assertEquals(-1, Chunks.toChunkPos(-1, 6)); + assertEquals(1, Chunks.toChunkPos(100, 6)); + assertEquals(3, Chunks.toChunkPos(200, 6)); } @Test public void testCalcChunkPos() { org.joml.Vector3i temp = new org.joml.Vector3i(); - assertTrue(ChunkMath.calcChunkPos(700, 700, 700, temp).equals(21, 10, 21)); - assertTrue(ChunkMath.calcChunkPos(200, 700, -1, temp).equals(6, 10, -1)); - assertTrue(ChunkMath.calcChunkPos(200, 200, 200, temp).equals(6, 3, 6)); - assertTrue(ChunkMath.calcChunkPos(10, 10, 10, temp).equals(0, 0, 0)); - } - - @Test - public void testChunkRegionAroundWorldPos() { - assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 100), - new BlockRegion(-4, -2, -4, 3, 1, 3)); - assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(-30, -30, -30), 100), - new BlockRegion(-5, -3, -5, 2, 1, 2)); - assertEquals(ChunkMath.getChunkRegionAroundWorldPos(new org.joml.Vector3i(0, 0, 0), 10), - new BlockRegion(-1, -1, -1, 0, 0, 0)); + assertEquals(new Vector3i(21, 10, 21), Chunks.toChunkPos(700, 700, 700, temp)); + assertEquals(new Vector3i(6, 10, -1), Chunks.toChunkPos(200, 700, -1, temp)); + assertEquals(new Vector3i(6, 3, 6), Chunks.toChunkPos(200, 200, 200, temp)); + assertEquals(new Vector3i(0, 0, 0), Chunks.toChunkPos(10, 10, 10, temp)); } - @Test public void testFloatingPointCalcChunkPos() { - org.joml.Vector3i temp = new org.joml.Vector3i(); - assertTrue(ChunkMath.calcChunkPos(31.9f, 64.1f, 32.5f, temp).equals(0, 1, 1), temp.toString()); - assertTrue(ChunkMath.calcChunkPos(32.9f, 63.9f, 32.9f, temp).equals(1, 0, 1), temp.toString()); - assertTrue(ChunkMath.calcChunkPos(31.3f, 63.9f, 31.9f, temp).equals(0, 0, 0), temp.toString()); - assertTrue(ChunkMath.calcChunkPos(31.6f, 64.5f, 32.1f, temp).equals(0, 1, 1), temp.toString()); - assertTrue(ChunkMath.calcChunkPos(.1f, -.2f, -.8f, temp).equals(0, -1, -1), temp.toString()); - assertTrue(ChunkMath.calcChunkPos(-.1f, -.99f, 2f, temp).equals(-1, -1, 0), temp.toString()); + Vector3i temp = new Vector3i(); + assertEquals(new Vector3i(0, 1, 1), Chunks.toChunkPos(31.9f, 64.1f, 32.5f, temp)); + assertEquals(new Vector3i(1, 0, 1), Chunks.toChunkPos(32.9f, 63.9f, 32.9f, temp)); + assertEquals(new Vector3i(0, 0, 0), Chunks.toChunkPos(31.3f, 63.9f, 31.9f, temp)); + assertEquals(new Vector3i(0, 1, 1), Chunks.toChunkPos(31.6f, 64.5f, 32.1f, temp)); + assertEquals(new Vector3i(0, -1, -1), Chunks.toChunkPos(.1f, -.2f, -.8f, temp)); + assertEquals(new Vector3i(-1, -1, 0), Chunks.toChunkPos(-.1f, -.99f, 2f, temp)); + + assertEquals(new Vector3i(0, 1, 1), Chunks.toChunkPos(new Vector3f(31.9f, 64.1f, 32.5f), temp)); + assertEquals(new Vector3i(1, 0, 1), Chunks.toChunkPos(new Vector3f(32.9f, 63.9f, 32.9f), temp)); + assertEquals(new Vector3i(0, 0, 0), Chunks.toChunkPos(new Vector3f(31.3f, 63.9f, 31.9f), temp)); + assertEquals(new Vector3i(0, 1, 1), Chunks.toChunkPos(new Vector3f(31.6f, 64.5f, 32.1f), temp)); + assertEquals(new Vector3i(0, -1, -1), Chunks.toChunkPos(new Vector3f(.1f, -.2f, -.8f), temp)); + assertEquals(new Vector3i(-1, -1, 0), Chunks.toChunkPos(new Vector3f(-.1f, -.99f, 2f), temp)); } - } diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java index dde835bfadd..7d39a32898a 100644 --- a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.terasology.math.Side; import java.util.ArrayList; import java.util.Collection; @@ -37,6 +38,23 @@ public class BlockRegionTest { + @Test + public void testGetEdgeRegion() { + BlockRegion region = new BlockRegion(new Vector3i(16, 0, 16)).setSize(16, 128, 16); + assertEquals(new BlockRegion(16, 0, 16, 16, 127, 31), region.face(Side.LEFT, + new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(31, 0, 16, 31, 127, 31), region.face(Side.RIGHT, + new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(16, 0, 16, 31, 127, 16), region.face(Side.FRONT, + new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(16, 0, 31, 31, 127, 31), region.face(Side.BACK, + new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(16, 127, 16, 31, 127, 31), region.face(Side.TOP, + new BlockRegion(BlockRegion.INVALID))); + assertEquals(new BlockRegion(16, 0, 16, 31, 0, 31), region.face(Side.BOTTOM, + new BlockRegion(BlockRegion.INVALID))); + } + @Test void getMinMax() { final Vector3i min = new Vector3i(1, 2, 3); diff --git a/engine/src/main/java/org/terasology/math/ChunkMath.java b/engine/src/main/java/org/terasology/math/ChunkMath.java index 8f8dc785190..14722f0fdc8 100644 --- a/engine/src/main/java/org/terasology/math/ChunkMath.java +++ b/engine/src/main/java/org/terasology/math/ChunkMath.java @@ -29,8 +29,10 @@ /** * Collection of math functions. - * + * @deprecated This class is scheduled for removal in an upcoming version. + * Use the JOML implementation instead: {@link org.terasology.world.chunks.Chunks}. */ +@Deprecated public final class ChunkMath { private ChunkMath() { @@ -487,7 +489,11 @@ public static Region3i getChunkRegionAroundWorldPos(Vector3i pos, int extent) { * @param pos the world position * @param extent the extent * @return chunk region + * @deprecated This is scheduled for removal in an upcoming version + * method will be replaced with JOML implementation {@link org.terasology.world.chunks.Chunks#toChunkRegion(BlockRegion, BlockRegion)}. + * */ + @Deprecated public static BlockRegion getChunkRegionAroundWorldPos(Vector3ic pos, int extent) { org.joml.Vector3i temp = new org.joml.Vector3i(); org.joml.Vector3i minChunk = calcChunkPos(temp.set(pos).add(-extent, -extent, -extent), new org.joml.Vector3i()); @@ -570,7 +576,9 @@ public static Region3i getEdgeRegion(Region3i region, Side side) { * @param side the side to border * @param dest will hold the result * @return dest + * @deprecated use {@link BlockRegion#face(Side, BlockRegion)} */ + @Deprecated public static BlockRegion getEdgeRegion(BlockRegionc region, Side side, BlockRegion dest) { switch (side) { case TOP: diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegion.java b/engine/src/main/java/org/terasology/world/block/BlockRegion.java index d03c50215a5..c9b89373ef0 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegion.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegion.java @@ -8,6 +8,7 @@ import org.joml.RoundingMode; import org.joml.Vector3i; import org.joml.Vector3ic; +import org.terasology.math.Side; import java.util.Iterator; import java.util.Optional; @@ -489,6 +490,19 @@ public BlockRegion transform(Matrix4fc m) { return transform(m, this); } + /** + * Restrict this region to a 1-width region that borders the provided {@link Side} of a region. + *

+ * The resulting region is a subset of this region, i.e., the intersection of the face region with the source region + * is exactly the face region. + * + * @param side the side of the region + * @return this region (after modification) + */ + public BlockRegion face(Side side) { + return face(side, this); + } + // ---------------------------------------------------------------------------------------------------------------// /** diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegionc.java b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java index f582ad6071d..837e64b9d10 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegionc.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java @@ -14,6 +14,7 @@ import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; +import org.terasology.math.Side; import java.util.Iterator; import java.util.Optional; @@ -494,6 +495,37 @@ default BlockRegion expand(Vector3ic vec, BlockRegion dest) { */ BlockRegion transform(Matrix4fc m, BlockRegion dest); + // -- face -------------------------------------------------------------------------------------------------------// + + /** + * Calculates a 1 width region that borders the provided {@link Side} of a region. + *

+ * The resulting region is a subset of this region, i.e., the intersection of the face region with the source region + * is exactly the face region. + * + * @param side the side of the region + * @param dest will hold the result + * @return dest + */ + default BlockRegion face(Side side, BlockRegion dest) { + switch (side) { + case TOP: + return dest.set(this.minX(), this.maxY(), this.minZ(), this.maxX(), this.maxY(), this.maxZ()); + case BOTTOM: + return dest.set(this.minX(), this.minY(), this.minZ(), this.maxX(), this.minY(), this.maxZ()); + case LEFT: + return dest.set(this.minX(), this.minY(), this.minZ(), this.minX(), this.maxY(), this.maxZ()); + case RIGHT: + return dest.set(this.maxX(), this.minY(), this.minZ(), this.maxX(), this.maxY(), this.maxZ()); + case FRONT: + return dest.set(this.minX(), this.minY(), this.minZ(), this.maxX(), this.maxY(), this.minZ()); + case BACK: + return dest.set(this.minX(), this.minY(), this.maxZ(), this.maxX(), this.maxY(), this.maxZ()); + default: + return dest.set(this); + } + } + // -- CHECKS -----------------------------------------------------------------------------------------------------// /** diff --git a/engine/src/main/java/org/terasology/world/chunks/ChunkConstants.java b/engine/src/main/java/org/terasology/world/chunks/ChunkConstants.java index 313d63c72d3..96020e56cfe 100644 --- a/engine/src/main/java/org/terasology/world/chunks/ChunkConstants.java +++ b/engine/src/main/java/org/terasology/world/chunks/ChunkConstants.java @@ -22,9 +22,13 @@ import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; + /** + * @deprecated This method is scheduled for removal in an upcoming version. + * Use the JOML implementation instead: {@link org.terasology.world.chunks.Chunks}. */ @API +@Deprecated public final class ChunkConstants { public static final int SIZE_X = 32; public static final int SIZE_Y = 64; diff --git a/engine/src/main/java/org/terasology/world/chunks/Chunks.java b/engine/src/main/java/org/terasology/world/chunks/Chunks.java new file mode 100644 index 00000000000..fc0bd655903 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/chunks/Chunks.java @@ -0,0 +1,306 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.chunks; + +import org.joml.Math; +import org.joml.RoundingMode; +import org.joml.Vector3fc; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.module.sandbox.API; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; + +@API +public final class Chunks { + public static final int SIZE_X = 32; + public static final int SIZE_Y = 64; + public static final int SIZE_Z = 32; + + public static final int INNER_CHUNK_POS_FILTER_X = Integer.highestOneBit(SIZE_X) - 1; + public static final int INNER_CHUNK_POS_FILTER_Y = Integer.highestOneBit(SIZE_Y) - 1; + public static final int INNER_CHUNK_POS_FILTER_Z = Integer.highestOneBit(SIZE_Z) - 1; + + public static final int POWER_X = Integer.numberOfTrailingZeros(SIZE_X); + public static final int POWER_Y = Integer.numberOfTrailingZeros(SIZE_Y); + public static final int POWER_Z = Integer.numberOfTrailingZeros(SIZE_Z); + + public static final byte MAX_LIGHT = 0x0f; // max light for a light source 0-15 + public static final byte MAX_SUNLIGHT = 0x0f; // max sunlight for sunlight bounded 0-15 + public static final byte MAX_SUNLIGHT_REGEN = 63; + public static final byte SUNLIGHT_REGEN_THRESHOLD = 48; + + public static final Vector3ic CHUNK_POWER = new Vector3i(POWER_X, POWER_Y, POWER_Z); + public static final Vector3ic CHUNK_SIZE = new Vector3i(SIZE_X, SIZE_Y, SIZE_Z); + public static final Vector3ic INNER_CHUNK_POS_FILTER = new org.joml.Vector3i(INNER_CHUNK_POS_FILTER_X, INNER_CHUNK_POS_FILTER_Y, INNER_CHUNK_POS_FILTER_Z); + public static final BlockRegionc CHUNK_REGION = new BlockRegion(0, 0, 0).setSize(CHUNK_SIZE); + + public static final Vector3ic LOCAL_REGION_EXTENTS = new Vector3i(1, 1, 1); + + private Chunks() { + } + + /** + * Returns the chunk coordinate given the position and the chunk power. + * + * @param val The coordinate of the block + * @param chunkPower the size of the chunk in powers of 2 + * @return The coordinate of the chunk + */ + public static int toChunkPos(int val, int chunkPower) { + return (val >> chunkPower); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * This uses the default power {@link #POWER_X}. + * + * @param x the x component + * @return The coordinate of the chunk + */ + public static int toChunkPosX(int x) { + return toChunkPos(x, CHUNK_POWER.x()); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * This uses the default power {@link #POWER_Y} + * + * @param y the y component + * @return The coordinate of the chunk + */ + public static int toChunkPosY(int y) { + return toChunkPos(y, CHUNK_POWER.y()); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * This uses the default power {@link #POWER_Z} + * + * @param z the z component + * @return The coordinate of the chunk + */ + public static int toChunkPosZ(int z) { + return toChunkPos(z, CHUNK_POWER.z()); + } + + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * + *

default chunk size ({@link Chunks#SIZE_X}, {@link Chunks#SIZE_Y}, {@link + * Chunks#SIZE_Z})

+ * + * @param worldPos absolute position of the block + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(Vector3fc worldPos, Vector3i dest) { + return toChunkPos(worldPos.x(), worldPos.y(), worldPos.z(), POWER_X, POWER_Y, POWER_Z, dest); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * This uses the default power ({@link #POWER_X}, {@link #POWER_Y}, {@link #POWER_Z}) + * + *

default chunk size ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z})

+ * + * @param x absolute x coordinate of the block + * @param y absolute y coordinate of the block + * @param z absolute z coordinate of the block + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(int x, int y, int z, Vector3i dest) { + return toChunkPos(x, y, z, POWER_X, POWER_Y, POWER_Z, dest); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * + *

Chunk size is in powers of 2 (2, 4, 8, 16, ...)

+ * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + * @param chunkX the x unit size of the chunk in powers of 2 + * @param chunkY the y unit size of the chunk in powers of 2 + * @param chunkZ the z unit size of the chunk in powers of 2 + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(float x, float y, float z, int chunkX, int chunkY, int chunkZ, Vector3i dest) { + return toChunkPos( + Math.roundUsing(x, RoundingMode.FLOOR), + Math.roundUsing(y, RoundingMode.FLOOR), + Math.roundUsing(z, RoundingMode.FLOOR), chunkX, chunkY, chunkZ, dest); + } + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * + *

Chunk size is in powers of 2 (2, 4, 8, 16, ...)

+ * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(float x, float y, float z, Vector3i dest) { + return toChunkPos( + Math.roundUsing(x, RoundingMode.FLOOR), + Math.roundUsing(y, RoundingMode.FLOOR), + Math.roundUsing(z, RoundingMode.FLOOR), POWER_X, POWER_Y, POWER_Z, dest); + } + + + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * + *

Chunk size is in powers of 2 (2, 4, 8, 16, ...)

+ * + * @param x the x coordinate of the block + * @param y the y coordinate of the block + * @param z the z coordinate of the block + * @param chunkX the x unit size of the chunk in powers of 2 + * @param chunkY the y unit size of the chunk in powers of 2 + * @param chunkZ the z unit size of the chunk in powers of 2 + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(int x, int y, int z, int chunkX, int chunkY, int chunkZ, org.joml.Vector3i dest) { + return dest.set( + toChunkPos(x, chunkX), + toChunkPos(y, chunkY), + toChunkPos(z, chunkZ)); + } + /** + * Maps a {@link BlockRegion} to the chunks that intersect the {@link BlockRegion}. + * + * @param region a bounding box that is contained + * @param chunkX the x unit size of the chunk in powers of 2 + * @param chunkY the y unit size of the chunk in powers of 2 + * @param chunkZ the z unit size of the chunk in powers of 2 + * @param dest will hold the result + * @return dest + */ + public static BlockRegion toChunkRegion(BlockRegion region, int chunkX, int chunkY, int chunkZ, BlockRegion dest) { + return dest. + set(toChunkPos(region.minX(), chunkX), toChunkPos(region.minY(), chunkY), toChunkPos(region.minZ(), chunkZ), + toChunkPos(region.maxX(), chunkX), toChunkPos(region.maxY(), chunkY), toChunkPos(region.maxZ(), chunkZ)); + } + + /** + * Maps a {@link BlockRegion} to the relative chunks that intersect the {@link BlockRegion}. + * + * @param region a bounding box that is contained + * @param chunkPower the size of the chunk in powers of 2 + * @param dest will hold the result + * @return dest + */ + public static BlockRegion toChunkRegion(BlockRegion region, Vector3ic chunkPower, BlockRegion dest) { + return toChunkRegion(region, chunkPower.x(), chunkPower.y(), chunkPower.z(), dest); + } + + + /** + * Maps a {@link BlockRegion} to the chunks that intersect the {@link BlockRegion}. + * This uses the default power ({@link Chunks#POWER_X}, {@link Chunks#POWER_Y}, {@link Chunks#POWER_Z}) + * + * @param region a bounding box that is contained + * @param dest will hold the result + * @return dest + */ + public static BlockRegion toChunkRegion(BlockRegion region, BlockRegion dest) { + return toChunkRegion(region, Chunks.POWER_X, Chunks.POWER_Y, Chunks.POWER_Z, dest); + } + + /** + * Returns the internal position of a block within a chunk. + * + * @param worldPos the world position of a block + * @param filter the length of the chunk - 1 + * @return the relative position of the chunk + */ + public static int toRelative(int worldPos, int filter) { + return worldPos & filter; + } + + + /** + * the relative position from the x axis from the (0,0,0) corner. + * + * @param blockX absolute x position + * @return relative position for x axis + */ + public static int toRelativeX(int blockX) { + return toRelative(blockX, Chunks.INNER_CHUNK_POS_FILTER.x()); + } + + /** + * the relative position from the y axis from the (0,0,0) corner. + * + * @param blockY absolute y position + * @return relative position for y axis + */ + public static int toRelativeY(int blockY) { + return toRelative(blockY, Chunks.INNER_CHUNK_POS_FILTER.y()); + } + + /** + * the relative position from the z axis from the (0,0,0) corner. + * @param blockZ absolute z position + * @return relative position for z axis + */ + public static int toRelativeZ(int blockZ) { + return toRelative(blockZ, Chunks.INNER_CHUNK_POS_FILTER.z()); + } + /** + * the relative position in the nearest chunk from the (0,0,0) corner. + * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). + * + * @param worldPos world position + * @param dest will hold the result + * @return dest + */ + public static Vector3i toRelative(Vector3ic worldPos, Vector3i dest) { + return toRelative(worldPos.x(), worldPos.y(), worldPos.z(), INNER_CHUNK_POS_FILTER, dest); + } + + /** + * the relative position in the nearest chunk from the (0,0,0) corner. + * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). + * + * @param x the x world position + * @param y the y world position + * @param z the z world position + * @param chunkFilterSize relative within a chunk for (x - 1, y - 1, z - 1) + * @param dest will hold the result + * @return dest + */ + public static Vector3i toRelative(int x, int y, int z, Vector3ic chunkFilterSize, Vector3i dest) { + return dest.set(toRelative(x, chunkFilterSize.x()), toRelative(y, chunkFilterSize.y()), toRelative(z, chunkFilterSize.z())); + } + + + /** + * Works out whether the given block resides inside the given chunk. + *

+ * Both positions must be given as world position, not local position. In addition, the chunk position must be given + * in chunk coordinates, not in block coordinates. + *

+ * For example, using chunks of width 32, a block with x coordinate of 33 will be counted as inside a chunk with x + * coordinate of 1. + * + * @param blockWorldPos the block to check for + * @param chunkPos the chunk to check in + * @return whether the block is inside the chunk + */ + public static boolean inChunk(Vector3ic blockWorldPos, Vector3ic chunkPos) { + return toChunkPos(blockWorldPos.x(), POWER_X) == chunkPos.x() + && toChunkPos(blockWorldPos.y(), POWER_Y) == chunkPos.y() + && toChunkPos(blockWorldPos.z(), POWER_Z) == chunkPos.z(); + } +} From e796f62a2df9c614ccf427dcee333f8aa5ca6467 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 14:00:18 -0800 Subject: [PATCH 065/259] fix(#4319): add attchmentSide to getBlockForPlacement (#4352) --- .../org/terasology/world/block/family/MultiConnectFamily.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java index c213b59ff55..7e602e225f4 100644 --- a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java @@ -191,7 +191,7 @@ public Block getBlockForPlacement(BlockPlacementData data) { */ @Override public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - BlockPlacementData data = new BlockPlacementData(JomlUtil.from(location), null, new Vector3f()); + BlockPlacementData data = new BlockPlacementData(JomlUtil.from(location), attachmentSide, new Vector3f()); return getBlockForPlacement(data); } From 076902a53ca3f5fbed50729608de54aa454246e1 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 15:09:21 -0800 Subject: [PATCH 066/259] feat(JOML): migrate Voronoi (#4340) --- .../terasology/utilities/procedural/Voronoi.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/engine/src/main/java/org/terasology/utilities/procedural/Voronoi.java b/engine/src/main/java/org/terasology/utilities/procedural/Voronoi.java index f307cf1fab1..6b361466fb1 100644 --- a/engine/src/main/java/org/terasology/utilities/procedural/Voronoi.java +++ b/engine/src/main/java/org/terasology/utilities/procedural/Voronoi.java @@ -15,8 +15,9 @@ */ package org.terasology.utilities.procedural; -import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector2f; +import org.joml.Math; +import org.joml.RoundingMode; +import org.joml.Vector2f; import java.util.Random; @@ -60,11 +61,11 @@ public VoronoiResult[] getClosestPoints(Vector2f at, int numPoints) { result.distance = Float.MAX_VALUE; } - at.scale(DENSITY_ADJUSTMENT); + at.mul(DENSITY_ADJUSTMENT); at.add(offset); - int cellX = TeraMath.floorToInt(at.x); - int cellY = TeraMath.floorToInt(at.y); + int cellX = Math.roundUsing(at.x, RoundingMode.FLOOR); + int cellY = Math.roundUsing(at.y, RoundingMode.FLOOR); processCell(cellX, cellY, at, results); @@ -103,7 +104,7 @@ public VoronoiResult[] getClosestPoints(Vector2f at, int numPoints) { } for (VoronoiResult result : results) { - result.delta.scale(INVERSE_DENSITY_ADJUSTMENT); + result.delta.mul(INVERSE_DENSITY_ADJUSTMENT); result.distance *= INVERSE_DENSITY_ADJUSTMENT * INVERSE_DENSITY_ADJUSTMENT; } From 0a23982639ee6bf016f9ed9b255fab5ebca71b01 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 15:33:35 -0800 Subject: [PATCH 067/259] feat(JOML): migrate BlockSelection (#4336) Co-authored-by: Tobias Nett --- .../selection/ApplyBlockSelectionEvent.java | 7 ++-- ...LocalPlayerBlockSelectionByItemSystem.java | 16 +++++---- .../selection/MovableSelectionEndEvent.java | 7 ++-- .../selection/BlockSelectionRenderSystem.java | 27 ++++++--------- .../selection/BlockSelectionRenderer.java | 22 +++++++++++++ .../selection/BlockSelectionComponent.java | 6 ++-- .../world/selection/BlockSelectionSystem.java | 33 ++++++++----------- 7 files changed, 65 insertions(+), 53 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java b/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java index b30ac63b35c..cf16dad9b41 100644 --- a/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java +++ b/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java @@ -19,6 +19,7 @@ import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.Event; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; /** * This event is fired once a player finished a selection using an item with a BlockSelectionComponent. The item used @@ -27,15 +28,15 @@ */ @API public class ApplyBlockSelectionEvent implements Event { - private final Region3i selection; + private final BlockRegion selection; private final EntityRef selectedItemEntity; - public ApplyBlockSelectionEvent(EntityRef selectedItemEntity, Region3i selection) { + public ApplyBlockSelectionEvent(EntityRef selectedItemEntity, BlockRegion selection) { this.selectedItemEntity = selectedItemEntity; this.selection = selection; } - public Region3i getSelection() { + public BlockRegion getSelection() { return selection; } diff --git a/engine/src/main/java/org/terasology/logic/selection/LocalPlayerBlockSelectionByItemSystem.java b/engine/src/main/java/org/terasology/logic/selection/LocalPlayerBlockSelectionByItemSystem.java index d5dd532aa81..65207032765 100644 --- a/engine/src/main/java/org/terasology/logic/selection/LocalPlayerBlockSelectionByItemSystem.java +++ b/engine/src/main/java/org/terasology/logic/selection/LocalPlayerBlockSelectionByItemSystem.java @@ -15,6 +15,9 @@ */ package org.terasology.logic.selection; +import org.joml.RoundingMode; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; @@ -25,10 +28,8 @@ import org.terasology.logic.common.ActivateEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.In; +import org.terasology.world.block.BlockRegion; import org.terasology.world.selection.BlockSelectionComponent; import org.terasology.world.selection.event.SetBlockSelectionEndingPointEvent; import org.terasology.world.selection.event.SetBlockSelectionStartingPointEvent; @@ -93,13 +94,14 @@ public void onCamTargetChanged(CameraTargetChangedEvent event, EntityRef entity) return; } - Vector3f targetLocation = locationComponent.getWorldPosition(); + Vector3f targetLocation = locationComponent.getWorldPosition(new Vector3f()); if (blockSelectionComponent.isMovable) { - Region3i region = blockSelectionComponent.currentSelection; - blockSelectionComponent.currentSelection = Region3i.createFromCenterExtents(new Vector3i(targetLocation.x, targetLocation.y, targetLocation.z), - new Vector3i(region.sizeX()/2, 0, region.sizeZ()/2)); + Vector3i pos = new Vector3i(targetLocation, RoundingMode.FLOOR); + Vector3i size = blockSelectionComponent.currentSelection.getSize(new Vector3i()); + blockSelectionComponent.currentSelection.set( + pos, pos).expand(size.x() / 2, 0, size.z() / 2); blockSelectionComponentEntity.saveComponent(blockSelectionComponent); return; diff --git a/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java b/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java index feb844bba2d..6e8b41a96aa 100644 --- a/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java +++ b/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java @@ -18,6 +18,7 @@ import org.terasology.module.sandbox.API; import org.terasology.entitySystem.event.Event; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockRegion; /** * This event is sent when the player finalizes the position of a moving selection by clicking the left mouse button. @@ -29,13 +30,13 @@ public class MovableSelectionEndEvent implements Event { /** * The final position of the selected region */ - private Region3i finalRegion; + private BlockRegion finalRegion; - public MovableSelectionEndEvent(Region3i selectedRegion) { + public MovableSelectionEndEvent(BlockRegion selectedRegion) { this.finalRegion = selectedRegion; } - public Region3i getFinalRegion() { + public BlockRegion getFinalRegion() { return this.finalRegion; } } diff --git a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderSystem.java b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderSystem.java index 83917b301ab..7ea075d32d8 100644 --- a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderSystem.java +++ b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderSystem.java @@ -15,17 +15,19 @@ */ package org.terasology.rendering.world.selection; -import org.terasology.utilities.Assets; +import org.joml.Vector2i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.RenderSystem; -import org.terasology.math.geom.Vector2i; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.In; import org.terasology.rendering.assets.texture.Texture; +import org.terasology.utilities.Assets; +import org.terasology.world.block.BlockRegion; import org.terasology.world.selection.BlockSelectionComponent; import java.util.HashMap; @@ -43,10 +45,9 @@ public class BlockSelectionRenderSystem extends BaseComponentSystem implements R private EntityManager entityManager; /** - * This map will contain one reusable selection renderer per texture width/height pair. - * This should be a reasonable compromise between no caching and caching too many renderers. - * While it is possible that the number of cached renderers could grow out of control over time, - * in practice most textures should be a standard size. + * This map will contain one reusable selection renderer per texture width/height pair. This should be a reasonable + * compromise between no caching and caching too many renderers. While it is possible that the number of cached + * renderers could grow out of control over time, in practice most textures should be a standard size. */ private Map cachedBlockSelectionRendererByTextureDimensionsMap = new HashMap<>(); @@ -82,16 +83,8 @@ private void renderOverlayForOneBlockSelection(BlockSelectionComponent blockSele selectionRenderer.renderMark(blockSelectionComponent.startPosition); } } else { - Vector3i size = blockSelectionComponent.currentSelection.size(); - Vector3i block = new Vector3i(); - for (int z = 0; z < size.z; z++) { - for (int y = 0; y < size.y; y++) { - for (int x = 0; x < size.x; x++) { - block.set(x, y, z); - block.add(blockSelectionComponent.currentSelection.min()); - selectionRenderer.renderMark(block); - } - } + for (Vector3ic pos : blockSelectionComponent.currentSelection) { + selectionRenderer.renderMark(pos); } } selectionRenderer.endRenderOverlay(); diff --git a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java index fc9341810a8..270694446b7 100644 --- a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java @@ -15,6 +15,7 @@ */ package org.terasology.rendering.world.selection; +import org.joml.Vector3ic; import org.lwjgl.opengl.GL11; import org.terasology.math.JomlUtil; import org.terasology.math.geom.Rect2f; @@ -110,6 +111,13 @@ public void endRenderOverlay() { defaultTextured.deactivateFeature(ShaderProgramFeature.FEATURE_ALPHA_REJECT); } + /** + * + * @param blockPos + * @deprecated This method is scheduled for removal in an upcoming version. + * Use the JOML implementation instead: {@link #renderMark(Vector3ic)}. + */ + @Deprecated public void renderMark(Vector3i blockPos) { Vector3f cameraPos = getCameraPosition(); @@ -123,6 +131,20 @@ public void renderMark(Vector3i blockPos) { glPopMatrix(); } + + public void renderMark(Vector3ic blockPos) { + Vector3f cameraPos = getCameraPosition(); + + glPushMatrix(); + glTranslated(blockPos.x() - cameraPos.x, blockPos.y() - cameraPos.y, blockPos.z() - cameraPos.z); + + glMatrixMode(GL_MODELVIEW); + + overlayMesh.render(); + + glPopMatrix(); + } + public void renderMark2(Vector3i blockPos) { Vector3f cameraPos = getCameraPosition(); diff --git a/engine/src/main/java/org/terasology/world/selection/BlockSelectionComponent.java b/engine/src/main/java/org/terasology/world/selection/BlockSelectionComponent.java index ecfddb7c9fa..0df2c87cc22 100644 --- a/engine/src/main/java/org/terasology/world/selection/BlockSelectionComponent.java +++ b/engine/src/main/java/org/terasology/world/selection/BlockSelectionComponent.java @@ -15,11 +15,11 @@ */ package org.terasology.world.selection; +import org.joml.Vector3i; import org.terasology.entitySystem.Component; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import org.terasology.rendering.assets.texture.Texture; +import org.terasology.world.block.BlockRegion; /** *

@@ -43,7 +43,7 @@ public class BlockSelectionComponent implements Component { * when the starting point is set, then represents the region between the starting * and ending points after the ending point is set. */ - public Region3i currentSelection; + public BlockRegion currentSelection; /** * If true, block selection will be drawn diff --git a/engine/src/main/java/org/terasology/world/selection/BlockSelectionSystem.java b/engine/src/main/java/org/terasology/world/selection/BlockSelectionSystem.java index 659e3c2e08f..b9c7073d703 100644 --- a/engine/src/main/java/org/terasology/world/selection/BlockSelectionSystem.java +++ b/engine/src/main/java/org/terasology/world/selection/BlockSelectionSystem.java @@ -15,15 +15,16 @@ */ package org.terasology.world.selection; +import org.joml.RoundingMode; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.selection.event.SetBlockSelectionEndingPointEvent; import org.terasology.world.selection.event.SetBlockSelectionStartingPointEvent; @@ -34,10 +35,8 @@ @RegisterSystem(RegisterMode.AUTHORITY) public class BlockSelectionSystem extends BaseComponentSystem { - @ReceiveEvent(components = {LocationComponent.class}) - public void onStartSelectionAtEntity(SetBlockSelectionStartingPointEvent event, EntityRef entity) { - - LocationComponent locationComponent = entity.getComponent(LocationComponent.class); + @ReceiveEvent + public void onStartSelectionAtEntity(SetBlockSelectionStartingPointEvent event, EntityRef entity, LocationComponent locationComponent) { if (null == locationComponent) { // entity isn't LocationComponent, which shouldn't ever be the case return; @@ -49,18 +48,13 @@ public void onStartSelectionAtEntity(SetBlockSelectionStartingPointEvent event, return; } - Vector3f worldPosition = locationComponent.getWorldPosition(); - - Vector3i startPosition = new Vector3i(worldPosition.x, worldPosition.y, worldPosition.z); + Vector3i startPosition = new Vector3i(locationComponent.getWorldPosition(new Vector3f()), RoundingMode.FLOOR); blockSelectionComponent.startPosition = startPosition; - Vector3i endPosition = startPosition; - blockSelectionComponent.currentSelection = Region3i.createBounded(startPosition, endPosition); + blockSelectionComponent.currentSelection = new BlockRegion(startPosition); } - @ReceiveEvent(components = {LocationComponent.class}) - public void onEndSelectionAtEntity(SetBlockSelectionEndingPointEvent event, EntityRef entity) { - - LocationComponent locationComponent = entity.getComponent(LocationComponent.class); + @ReceiveEvent + public void onEndSelectionAtEntity(SetBlockSelectionEndingPointEvent event, EntityRef entity, LocationComponent locationComponent) { if (null == locationComponent) { // entity isn't LocationComponent, which shouldn't ever be the case return; @@ -72,13 +66,12 @@ public void onEndSelectionAtEntity(SetBlockSelectionEndingPointEvent event, Enti return; } - Vector3f worldPosition = locationComponent.getWorldPosition(); - - Vector3i endPosition = new Vector3i(worldPosition.x, worldPosition.y, worldPosition.z); + Vector3i endPosition = new Vector3i(locationComponent.getWorldPosition(new Vector3f()), RoundingMode.FLOOR); Vector3i startPosition = blockSelectionComponent.startPosition; if (null == startPosition) { startPosition = endPosition; } - blockSelectionComponent.currentSelection = Region3i.createBounded(startPosition, endPosition); + blockSelectionComponent.currentSelection = + new BlockRegion(startPosition).union(endPosition); } } From 9476a4cd580c60dafcb00aae60e35ef81ef6db9b Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 16:03:03 -0800 Subject: [PATCH 068/259] feat(JOML): migrate OnBlockItemPlaced (#4354) --- .../world/block/items/BlockItemSystem.java | 3 +- .../world/block/items/OnBlockItemPlaced.java | 68 ++++++++++++------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java index d3b180318c6..158946e60aa 100644 --- a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java +++ b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java @@ -29,7 +29,6 @@ import org.terasology.logic.characters.KinematicCharacterMover; import org.terasology.logic.common.ActivateEvent; import org.terasology.logic.inventory.ItemComponent; -import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.network.NetworkSystem; import org.terasology.physics.Physics; @@ -102,7 +101,7 @@ public void onPlaceBlock(ActivateEvent event, EntityRef item) { PlaceBlocks placeBlocks = new PlaceBlocks(placementPos, block, event.getInstigator()); worldProvider.getWorldEntity().send(placeBlocks); if (!placeBlocks.isConsumed()) { - item.send(new OnBlockItemPlaced(JomlUtil.from(placementPos), blockEntityRegistry.getBlockEntityAt(placementPos), event.getInstigator())); + item.send(new OnBlockItemPlaced(placementPos, blockEntityRegistry.getBlockEntityAt(placementPos), event.getInstigator())); } else { event.consume(); } diff --git a/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java b/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java index b8f7fac1acf..36ecf90ef74 100644 --- a/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java +++ b/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java @@ -1,23 +1,12 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.items; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.JomlUtil; /** * This event gets called whenever a block item is placed in the world @@ -26,10 +15,10 @@ public class OnBlockItemPlaced implements Event { /** * The position where the block is placed */ - private Vector3i position; + private Vector3i position = new Vector3i(); /** - * The entity corresponding to the placed block + * The entity corresponding to the placed block */ private EntityRef placedBlock; @@ -38,25 +27,56 @@ public class OnBlockItemPlaced implements Event { */ private EntityRef instigator = EntityRef.NULL; + /** + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #OnBlockItemPlaced(Vector3ic, EntityRef, EntityRef)}. + */ @Deprecated - public OnBlockItemPlaced(Vector3i pos, EntityRef placedBlock) { - this.position = pos; + public OnBlockItemPlaced(org.terasology.math.geom.Vector3i pos, EntityRef placedBlock) { + this.position = JomlUtil.from(pos); this.placedBlock = placedBlock; } - public OnBlockItemPlaced(Vector3i pos, EntityRef placedBlock, EntityRef instigator) { - this.position = pos; + /** + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #OnBlockItemPlaced(Vector3ic, EntityRef, EntityRef)}. + */ + @Deprecated + public OnBlockItemPlaced(org.terasology.math.geom.Vector3i pos, EntityRef placedBlock, EntityRef instigator) { + this.position = JomlUtil.from(pos); this.placedBlock = placedBlock; this.instigator = instigator; } - public Vector3i getPosition() { - return new Vector3i(position); + + /** + * + * @param pos the position that the block is placed + * @param placedBlock the block that is placed + * @param instigator the entity that places the block. A block placed without an instigator can be specified with {@link EntityRef#NULL} + */ + public OnBlockItemPlaced(Vector3ic pos, EntityRef placedBlock, EntityRef instigator) { + this.position.set(pos); + this.placedBlock = placedBlock; + this.instigator = instigator; + } + + /** + * @return world position of the placed block + */ + public Vector3ic getPosition() { + return position; } + /** + * @return The entity linked to the given block + */ public EntityRef getPlacedBlock() { return placedBlock; } + /** + * @return the entity that placed the block + */ public EntityRef getInstigator() { return instigator; } From a139160a8a1033a0c632fa3912c030cf7f751145 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 16:23:23 -0800 Subject: [PATCH 069/259] feat(JOML): migrate ParicleUpdateImpl (#4346) --- .../updating/ParticleUpdaterImpl.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/engine/src/main/java/org/terasology/particles/updating/ParticleUpdaterImpl.java b/engine/src/main/java/org/terasology/particles/updating/ParticleUpdaterImpl.java index 088b00eda2b..e32f63bdd09 100644 --- a/engine/src/main/java/org/terasology/particles/updating/ParticleUpdaterImpl.java +++ b/engine/src/main/java/org/terasology/particles/updating/ParticleUpdaterImpl.java @@ -1,32 +1,18 @@ -/* - * Copyright 2016 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.particles.updating; import com.google.common.base.Preconditions; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.module.ModuleManager; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3f; import org.terasology.module.ModuleEnvironment; import org.terasology.particles.ParticleDataMask; import org.terasology.particles.ParticlePool; @@ -54,7 +40,8 @@ public class ParticleUpdaterImpl implements ParticleUpdater { private static final Logger logger = LoggerFactory.getLogger(ParticleUpdaterImpl.class); /** - * Number used in determining how many particles to skip in each collision update step, as updating all particles is costly. + * Number used in determining how many particles to skip in each collision update step, as updating all particles is + * costly. */ private static final int PHYSICS_SKIP_NR = 100; @@ -182,7 +169,7 @@ public void configureEmitter(final ParticleEmitterComponent emitter) { * Maps a Generator function to the component it will be called on when new particles are emitted. * * @param generatorFunction The generator function to be used. - * @param componentClass The component class this function is being mapped to. + * @param componentClass The component class this function is being mapped to. */ private void mapGeneratorFunction(GeneratorFunction generatorFunction, Class componentClass) { Preconditions.checkArgument(!registeredGeneratorFunctions.containsKey(componentClass), @@ -197,7 +184,7 @@ private void mapGeneratorFunction(GeneratorFunction generatorFunction, Class componentClass) { Preconditions.checkArgument(!registeredAffectorFunctions.containsKey(componentClass), @@ -217,12 +204,12 @@ private void checkCollision(final ParticlePool pool, final int offset) { int i3 = i * 3; curr.set(pool.position[i3 + 0], pool.position[i3 + 1], pool.position[i3 + 2]); vel.set(pool.velocity[i3 + 0], pool.velocity[i3 + 1], pool.velocity[i3 + 2]); - halfVelDir.scale(0).add(vel).normalize().scale(0.5f); + halfVelDir.set(0).add(vel).normalize().mul(0.5f); curr.sub(halfVelDir); float dist = (vel.length() + 0.5f) * movingAvgDelta * PHYSICS_SKIP_NR * 1.5f; vel.normalize(); - HitResult hitResult = physics.rayTrace(JomlUtil.from(curr), JomlUtil.from(vel), dist, StandardCollisionGroup.WORLD); + HitResult hitResult = physics.rayTrace(curr, vel, dist, StandardCollisionGroup.WORLD); if (hitResult.isHit()) { pool.energy[i] = 0; } @@ -274,7 +261,7 @@ private void emitParticle(final ParticleEmitterComponent particleEmitter) { ); particleEmitter.particlePool.temporaryParticleData.position.add( - JomlUtil.from(particleEmitter.locationComponent.getWorldPosition()) + particleEmitter.locationComponent.getWorldPosition(new Vector3f()) ); particleEmitter.particlePool.storeTemporaryDataAt(index, ParticleDataMask.ALL.toInt()); @@ -306,8 +293,9 @@ private void updateEmitter(final ParticleEmitterComponent particleEmitter, final } /** - * Updates the specified particle emitter. - * Might cause the emitter to emit new particles or to be disabled once its lifetime runs out. + * Updates the specified particle emitter. Might cause the emitter to emit new particles or to be disabled once its + * lifetime runs out. + * * @param emitter the emitter to update * @param delta delta time */ @@ -320,10 +308,11 @@ private void updateParticleEmitters(final ParticleEmitterComponent emitter, fina } /** - * Updates the particle data inside the particle pool, referenced by the specified particle emitter. - * During a single update cycle, each pool is only updated once. - * In case multiple particle emitters are referencing it, it is only updated the first time it's encountered. - * The update involves updating the trajectory and life time (optionally dependent on collisions) + * Updates the particle data inside the particle pool, referenced by the specified particle emitter. During a single + * update cycle, each pool is only updated once. In case multiple particle emitters are referencing it, it is only + * updated the first time it's encountered. The update involves updating the trajectory and life time (optionally + * dependent on collisions) + * * @param particleSystem the particle system referencing the pool to update * @param delta delta time */ @@ -342,9 +331,9 @@ private void updateParticleData(final ParticleEmitterComponent particleSystem, f } /** - * Updates the particle emitters lifetime and disables or removes it potentially. - * In case the life time runs out, the emitter is disabled. - * In case no more particles in the pool are alive, the emitter is destroyed. + * Updates the particle emitters lifetime and disables or removes it potentially. In case the life time runs out, + * the emitter is disabled. In case no more particles in the pool are alive, the emitter is destroyed. + * * @param emitter emitter to update * @param delta delta time */ From d9bafec118ead99cb1bbda3c852caae565897d75 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 30 Dec 2020 22:29:53 -0800 Subject: [PATCH 070/259] feat(JOML): migrate CharacterSystem (#4349) --- .../org/terasology/logic/characters/CharacterSystem.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterSystem.java b/engine/src/main/java/org/terasology/logic/characters/CharacterSystem.java index ea62e195f07..d050ce0fa7c 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterSystem.java @@ -17,6 +17,7 @@ package org.terasology.logic.characters; import com.google.common.collect.Sets; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.Time; @@ -48,8 +49,6 @@ import org.terasology.logic.inventory.ItemComponent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.PlayerCharacterComponent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.network.ClientComponent; import org.terasology.network.NetworkSystem; import org.terasology.physics.CollisionGroup; @@ -434,9 +433,8 @@ public void update(float delta) { private boolean isDistanceToLarge(LocationComponent characterLocation, LocationComponent targetLocation, float maxInteractionRange) { float maxInteractionRangeSquared = maxInteractionRange * maxInteractionRange; - Vector3f positionDelta = new Vector3f(); - positionDelta.add(characterLocation.getWorldPosition()); - positionDelta.sub(targetLocation.getWorldPosition()); + Vector3f positionDelta = characterLocation.getWorldPosition(new Vector3f()); + positionDelta.sub(targetLocation.getWorldPosition(new Vector3f())); float interactionRangeSquared = positionDelta.lengthSquared(); // add a small epsilon to have rounding mistakes be in favor of the player: float epsilon = 0.00001f; From 8d2eec7233f770d20483bcfb55517a7b3e7c392f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 03:21:29 -0800 Subject: [PATCH 071/259] feat(JOML): migrate world renderer (#4333) --- .../rendering/world/RenderableWorld.java | 10 +-- .../rendering/world/RenderableWorldImpl.java | 74 +++++++++---------- .../rendering/world/WorldRendererImpl.java | 4 +- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java index be385e35b70..c26b6ab61e2 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java @@ -15,10 +15,10 @@ */ package org.terasology.rendering.world; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; import org.terasology.rendering.cameras.Camera; import org.terasology.rendering.world.viewDistance.ViewDistance; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.ChunkProvider; /** @@ -26,15 +26,15 @@ */ public interface RenderableWorld { - void onChunkLoaded(Vector3i chunkPosition); + void onChunkLoaded(Vector3ic chunkPosition); - void onChunkUnloaded(Vector3i chunkPosition); + void onChunkUnloaded(Vector3ic chunkPosition); boolean pregenerateChunks(); void update(); - boolean updateChunksInProximity(Region3i renderableRegion); + boolean updateChunksInProximity(BlockRegion renderableRegion); boolean updateChunksInProximity(ViewDistance viewDistance); diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index d9fb01d067d..0bc485a8a91 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -17,6 +17,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,10 +26,7 @@ import org.terasology.config.RenderingConfig; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.cameras.Camera; @@ -36,6 +35,7 @@ import org.terasology.rendering.world.viewDistance.ViewDistance; import org.terasology.world.ChunkView; import org.terasology.world.WorldProvider; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; @@ -67,7 +67,7 @@ class RenderableWorldImpl implements RenderableWorld { private ChunkTessellator chunkTessellator; private final ChunkMeshUpdateManager chunkMeshUpdateManager; private final List chunksInProximityOfCamera = Lists.newArrayListWithCapacity(MAX_LOADABLE_CHUNKS); - private Region3i renderableRegion = Region3i.empty(); + private BlockRegion renderableRegion = new BlockRegion(BlockRegion.INVALID); private ViewDistance currentViewDistance; private RenderQueuesHelper renderQueues; @@ -102,9 +102,9 @@ class RenderableWorldImpl implements RenderableWorld { } @Override - public void onChunkLoaded(Vector3i chunkCoordinates) { - if (renderableRegion.encompasses(chunkCoordinates)) { - Chunk chunk = chunkProvider.getChunk(chunkCoordinates); + public void onChunkLoaded(Vector3ic chunkCoordinates) { + if (renderableRegion.contains(chunkCoordinates)) { + Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkCoordinates)); if (chunk != null) { chunksInProximityOfCamera.add(chunk); Collections.sort(chunksInProximityOfCamera, new ChunkFrontToBackComparator()); @@ -115,13 +115,13 @@ public void onChunkLoaded(Vector3i chunkCoordinates) { } @Override - public void onChunkUnloaded(Vector3i chunkCoordinates) { - if (renderableRegion.encompasses(chunkCoordinates)) { + public void onChunkUnloaded(Vector3ic chunkCoordinates) { + if (renderableRegion.contains(chunkCoordinates)) { RenderableChunk chunk; Iterator iterator = chunksInProximityOfCamera.iterator(); while (iterator.hasNext()) { chunk = iterator.next(); - if (chunk.getPosition().equals(chunkCoordinates)) { + if (chunk.getPosition(new org.joml.Vector3i()).equals(chunkCoordinates)) { chunk.disposeMesh(); iterator.remove(); break; @@ -143,12 +143,12 @@ public boolean pregenerateChunks() { RenderableChunk chunk; ChunkMesh newMesh; ChunkView localView; - for (Vector3i chunkCoordinates : calculateRenderableRegion(renderingConfig.getViewDistance())) { - chunk = chunkProvider.getChunk(chunkCoordinates); + for (Vector3ic chunkCoordinates : calculateRenderableRegion(renderingConfig.getViewDistance())) { + chunk = chunkProvider.getChunk(JomlUtil.from(chunkCoordinates)); if (chunk == null) { pregenerationIsComplete = false; } else if (chunk.isDirty()) { - localView = worldProvider.getLocalView(chunkCoordinates); + localView = worldProvider.getLocalView(JomlUtil.from(chunkCoordinates)); if (localView == null) { continue; } @@ -196,33 +196,31 @@ public void update() { * @return True if the list was changed */ @Override - public boolean updateChunksInProximity(Region3i newRenderableRegion) { + public boolean updateChunksInProximity(BlockRegion newRenderableRegion) { if (!newRenderableRegion.equals(renderableRegion)) { - Vector3i chunkPosition; RenderableChunk chunk; + for (Vector3ic chunkPositionToRemove : renderableRegion) { + if (!newRenderableRegion.contains(chunkPositionToRemove)) { + Iterator nearbyChunks = chunksInProximityOfCamera.iterator(); + for (Iterator it = nearbyChunks; it.hasNext(); ) { + chunk = it.next(); + if (chunk.getPosition(new org.joml.Vector3i()).equals(chunkPositionToRemove)) { + chunk.disposeMesh(); + nearbyChunks.remove(); + break; + } - Iterator chunksToRemove = renderableRegion.subtract(newRenderableRegion); - while (chunksToRemove.hasNext()) { - chunkPosition = chunksToRemove.next(); - Iterator nearbyChunks = chunksInProximityOfCamera.iterator(); - while (nearbyChunks.hasNext()) { - chunk = nearbyChunks.next(); - if (chunk.getPosition().equals(chunkPosition)) { - chunk.disposeMesh(); - nearbyChunks.remove(); - break; } } } - boolean chunksHaveBeenAdded = false; - Iterator chunksToAdd = newRenderableRegion.subtract(renderableRegion); - while (chunksToAdd.hasNext()) { - chunkPosition = chunksToAdd.next(); - chunk = chunkProvider.getChunk(chunkPosition); - if (chunk != null) { - chunksInProximityOfCamera.add(chunk); - chunksHaveBeenAdded = true; + for (Vector3ic chunkPositionToAdd : newRenderableRegion) { + if (!renderableRegion.contains(chunkPositionToAdd)) { + chunk = chunkProvider.getChunk(JomlUtil.from(chunkPositionToAdd)); + if (chunk != null) { + chunksInProximityOfCamera.add(chunk); + chunksHaveBeenAdded = true; + } } } @@ -247,11 +245,11 @@ public boolean updateChunksInProximity(ViewDistance newViewDistance) { } } - private Region3i calculateRenderableRegion(ViewDistance newViewDistance) { + private BlockRegion calculateRenderableRegion(ViewDistance newViewDistance) { Vector3i cameraCoordinates = calcCameraCoordinatesInChunkUnits(); Vector3ic renderableRegionSize = newViewDistance.getChunkDistance(); Vector3i renderableRegionExtents = new Vector3i(renderableRegionSize.x() / 2, renderableRegionSize.y() / 2, renderableRegionSize.z() / 2); - return Region3i.createFromCenterExtents(cameraCoordinates, renderableRegionExtents); + return new BlockRegion(cameraCoordinates).expand(renderableRegionExtents); } /** @@ -435,7 +433,7 @@ public String getMetrics() { private static float squaredDistanceToCamera(RenderableChunk chunk, Vector3f cameraPosition) { // For performance reasons, to avoid instantiating too many vectors in a frequently called method, // comments are in use instead of appropriately named vectors. - Vector3f result = chunk.getPosition().toVector3f(); // chunk position in chunk coordinates + Vector3f result = new Vector3f(chunk.getPosition(new Vector3i())); // chunk position in chunk coordinates result.add(CHUNK_CENTER_OFFSET); // chunk center in chunk coordinates result.x *= ChunkConstants.SIZE_X; // chunk center in world coordinates @@ -456,7 +454,7 @@ private static class ChunkFrontToBackComparator implements Comparator Date: Thu, 31 Dec 2020 03:38:07 -0800 Subject: [PATCH 072/259] feat(JOML): migrate BlockEntitySystem (#4351) --- .../world/block/entity/BlockEntitySystem.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java index cb9023d7d6a..959489e6a5e 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/BlockEntitySystem.java @@ -15,7 +15,9 @@ */ package org.terasology.world.block.entity; +import org.joml.RoundingMode; import org.joml.Vector3f; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.audio.AudioManager; import org.terasology.audio.StaticSound; @@ -31,8 +33,6 @@ import org.terasology.logic.inventory.events.DropItemEvent; import org.terasology.logic.inventory.events.GiveItemEvent; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.physics.events.ImpulseEvent; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; @@ -48,7 +48,6 @@ import org.terasology.world.block.regions.BlockRegionComponent; import org.terasology.world.block.sounds.BlockSounds; -import java.math.RoundingMode; /** * Event handler for events affecting block entities @@ -88,12 +87,12 @@ public void doDestroy(DoDestroyEvent event, EntityRef entity, ActAsBlockComponen @ReceiveEvent(priority = EventPriority.PRIORITY_LOW) public void doDestroy(DoDestroyEvent event, EntityRef entity, BlockComponent blockComponent) { commonDestroyed(event, entity, blockComponent.block); - worldProvider.setBlock(blockComponent.position, blockManager.getBlock(BlockManager.AIR_ID)); + worldProvider.setBlock(blockComponent.getPosition(new Vector3i()), blockManager.getBlock(BlockManager.AIR_ID)); } @ReceiveEvent(priority = EventPriority.PRIORITY_TRIVIAL) public void defaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, BlockComponent blockComponent) { - Vector3i location = new Vector3i(blockComponent.position); + Vector3i location = blockComponent.getPosition(new Vector3i()); commonDefaultDropsHandling(event, entity, location, blockComponent.block); } @@ -106,22 +105,22 @@ public void defaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, // loop through all the blocks in this region and drop them for (Vector3ic location : blockRegion.region) { Block blockInWorld = worldProvider.getBlock(location); - commonDefaultDropsHandling(event, entity, JomlUtil.from(location), blockInWorld.getBlockFamily().getArchetypeBlock()); + commonDefaultDropsHandling(event, entity, location, blockInWorld.getBlockFamily().getArchetypeBlock()); } } else { // just drop the ActAsBlock block - Vector3i location = JomlUtil.from(new org.joml.Vector3i(blockRegion.region.center(new Vector3f()), org.joml.RoundingMode.HALF_UP)); + Vector3i location = new Vector3i(blockRegion.region.center(new Vector3f()), RoundingMode.HALF_UP); commonDefaultDropsHandling(event, entity, location, blockComponent.block.getArchetypeBlock()); } } else if (entity.hasComponent(LocationComponent.class)) { LocationComponent locationComponent = entity.getComponent(LocationComponent.class); - Vector3i location = new Vector3i(locationComponent.getWorldPosition(), RoundingMode.HALF_UP); + Vector3i location = new Vector3i(locationComponent.getWorldPosition(new Vector3f()), RoundingMode.HALF_UP); commonDefaultDropsHandling(event, entity, location, blockComponent.block.getArchetypeBlock()); } } } - public void commonDefaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, Vector3i location, Block block) { + public void commonDefaultDropsHandling(CreateBlockDropsEvent event, EntityRef entity, Vector3ic location, Block block) { BlockDamageModifierComponent blockDamageModifierComponent = event.getDamageType().getComponent(BlockDamageModifierComponent.class); float chanceOfBlockDrop = 1; @@ -170,7 +169,7 @@ private void commonDestroyed(DoDestroyEvent event, EntityRef entity, Block block // 'CoreAssets' from the engine EntityBuilder dustBuilder = entityManager.newBuilder("CoreAssets:dustEffect"); if (dustBuilder.hasComponent(LocationComponent.class)) { - dustBuilder.getComponent(LocationComponent.class).setWorldPosition(entity.getComponent(LocationComponent.class).getWorldPosition()); + dustBuilder.getComponent(LocationComponent.class).setWorldPosition(entity.getComponent(LocationComponent.class).getWorldPosition(new Vector3f())); dustBuilder.build(); } } @@ -184,8 +183,8 @@ private void commonDestroyed(DoDestroyEvent event, EntityRef entity, Block block } } - private void processDropping(EntityRef item, Vector3i location, float impulsePower) { - item.send(new DropItemEvent(location.toVector3f())); + private void processDropping(EntityRef item, Vector3ic location, float impulsePower) { + item.send(new DropItemEvent(new Vector3f(location))); item.send(new ImpulseEvent(random.nextVector3f(impulsePower, new Vector3f()))); } From c5a732fc3e40b5e169cf457458330f66add1b957 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 03:54:04 -0800 Subject: [PATCH 073/259] feat(JOML): add replacment methods and deprecates methods in MeshBuilder (#4318) Co-authored-by: Tobias Nett --- .../rendering/assets/mesh/MeshBuilder.java | 70 +++++++++++++++++-- .../skeletalmesh/SkeletalMeshDataBuilder.java | 13 +--- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java index 67fc576706a..91b897b844e 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java @@ -15,12 +15,14 @@ */ package org.terasology.rendering.assets.mesh; -import org.terasology.nui.Colorc; -import org.terasology.utilities.Assets; +import org.joml.Vector2fc; +import org.joml.Vector3fc; import org.terasology.assets.ResourceUrn; import org.terasology.math.geom.Vector2f; import org.terasology.math.geom.Vector3f; import org.terasology.module.sandbox.API; +import org.terasology.nui.Colorc; +import org.terasology.utilities.Assets; public class MeshBuilder { private static final float[] VERTICES = { @@ -74,6 +76,13 @@ public class MeshBuilder { private int vertexCount; private TextureMapper textureMapper; + /** + * + * @param v + * @return + * @deprecated This is scheduled for removal in an upcoming version + * method will be replaced with JOML implementation {@link #addVertex(Vector3fc)}. + */ public MeshBuilder addVertex(Vector3f v) { meshData.getVertices().add(v.x); meshData.getVertices().add(v.y); @@ -82,6 +91,24 @@ public MeshBuilder addVertex(Vector3f v) { return this; } + public MeshBuilder addVertex(Vector3fc v) { + meshData.getVertices().add(v.x()); + meshData.getVertices().add(v.y()); + meshData.getVertices().add(v.z()); + vertexCount++; + return this; + } + + /** + * + * @param v1 + * @param v2 + * @param v3 + * @param vn + * @return + * @deprecated This is scheduled for removal in an upcoming version + * method will be replaced with JOML implementation {@link #addPoly(Vector3fc, Vector3fc, Vector3fc, Vector3fc...)}. + */ public MeshBuilder addPoly(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f... vn) { for (int i = 0; i < vn.length + 1; i++) { addIndices(vertexCount, vertexCount + i + 2, vertexCount + i + 1); @@ -95,6 +122,27 @@ public MeshBuilder addPoly(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f... vn return this; } + /** + * + * @param v1 + * @param v2 + * @param v3 + * @param vn + * @return + */ + public MeshBuilder addPoly(Vector3fc v1, Vector3fc v2, Vector3fc v3, Vector3fc... vn) { + for (int i = 0; i < vn.length + 1; i++) { + addIndices(vertexCount, vertexCount + i + 2, vertexCount + i + 1); + } + addVertex(v1); + addVertex(v2); + addVertex(v3); + for (Vector3fc v : vn) { + addVertex(v); + } + return this; + } + public MeshBuilder addColor(Colorc c1, Colorc... colors) { meshData.getColors().add(c1.rf()); meshData.getColors().add(c1.gf()); @@ -115,10 +163,22 @@ public MeshBuilder addTexCoord(float x, float y) { return this; } + /** + * + * @param v + * @return + * + * @deprecated This is scheduled for removal in an upcoming version + * method will be replaced with JOML implementation {@link #addTexCoord(Vector2fc)}. + */ public MeshBuilder addTexCoord(Vector2f v) { return addTexCoord(v.x, v.y); } + public MeshBuilder addTexCoord(Vector2fc v) { + return addTexCoord(v.x(), v.y()); + } + public MeshBuilder addIndex(int index) { meshData.getIndices().add(index); return this; @@ -146,7 +206,7 @@ public Mesh build(ResourceUrn urn) { *

* Use the texture mapper to change how texture coordinates (u and v) are applied to each vertex. */ - public MeshBuilder addBox(Vector3f offset, Vector3f size, float u, float v) { + public MeshBuilder addBox(org.joml.Vector3f offset, org.joml.Vector3f size, float u, float v) { int vertexId = vertexCount; textureMapper.initialize(offset, size); for (int i = 0; i < VERTICES.length / 3; i++) { @@ -165,8 +225,8 @@ public void setTextureMapper(TextureMapper textureMapper) { @API public interface TextureMapper { - void initialize(Vector3f offset, Vector3f size); + void initialize(org.joml.Vector3f offset, org.joml.Vector3f size); - Vector2f map(int vertexIndex, float u, float v); + org.joml.Vector2fc map(int vertexIndex, float u, float v); } } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java index 6ea1f8809b9..f54067f0d5b 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java @@ -29,6 +29,7 @@ import java.util.List; /** + * */ public class SkeletalMeshDataBuilder { @@ -38,7 +39,6 @@ public class SkeletalMeshDataBuilder { private List vertices = new ArrayList<>(); private List normals = new ArrayList<>(); private TIntList indices = new TIntArrayList(); - private MeshBuilder.TextureMapper textureMapper; public SkeletalMeshDataBuilder() { @@ -70,13 +70,6 @@ public SkeletalMeshDataBuilder addMesh(Bone bone, MeshBuilder builder) { return addMesh(bone, builder.getMeshData()); } - public SkeletalMeshDataBuilder addBox(Bone bone, Vector3f offset, Vector3f size, float u, float v) { - MeshBuilder meshBuilder = new MeshBuilder(); - meshBuilder.setTextureMapper(textureMapper); - meshBuilder.addBox(JomlUtil.from(offset), JomlUtil.from(size), u, v); - return addMesh(bone, meshBuilder); - } - public SkeletalMeshDataBuilder addMesh(Bone bone, MeshData data) { TFloatList meshVertices = data.getVertices(); TIntList meshIndices = data.getIndices(); @@ -101,10 +94,6 @@ public SkeletalMeshDataBuilder addMesh(Bone bone, MeshData data) { return this; } - public void setTextureMapper(MeshBuilder.TextureMapper textureMapper) { - this.textureMapper = textureMapper; - } - public void setUvs(List uvs) { this.uvs.clear(); this.uvs.addAll(uvs); From 8c90f8643dab4ff3e3950c90c2c81112786e83ec Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 04:13:48 -0800 Subject: [PATCH 074/259] feat(JOML): migrate LocationComponent constructor (#4358) --- .../persistence/internal/StorageManagerTest.java | 2 +- .../org/terasology/logic/location/LocationComponent.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java index 5e2f602ccb2..1a0cddb6de9 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java @@ -209,7 +209,7 @@ public void testStoreAndRestoreOfPlayerWithoutCharacter() { @Test public void testPlayerRelevanceLocationSurvivesStorage() { Vector3f loc = new Vector3f(1, 2, 3); - character.addComponent(new LocationComponent(JomlUtil.from(loc))); + character.addComponent(new LocationComponent(loc)); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); diff --git a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java index a81f3d74f6f..d8bf5b7b8bb 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java @@ -66,10 +66,19 @@ public final class LocationComponent implements Component, ReplicationCheck { public LocationComponent() { } + /** + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #LocationComponent(Vector3fc)}. + */ + @Deprecated public LocationComponent(Vector3f position) { setLocalPosition(position); } + public LocationComponent(Vector3fc position) { + setLocalPosition(position); + } + /** * @return local rotation of location component * From 335982bc99774e885978beb399749b2f0d54888a Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 04:31:12 -0800 Subject: [PATCH 075/259] feat(JOML): migrate NameTagClientSystem (#4357) --- .../org/terasology/logic/nameTags/NameTagClientSystem.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/nameTags/NameTagClientSystem.java b/engine/src/main/java/org/terasology/logic/nameTags/NameTagClientSystem.java index 3726ef2e979..6eb0facc283 100644 --- a/engine/src/main/java/org/terasology/logic/nameTags/NameTagClientSystem.java +++ b/engine/src/main/java/org/terasology/logic/nameTags/NameTagClientSystem.java @@ -15,6 +15,8 @@ */ package org.terasology.logic.nameTags; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.entitySystem.entity.EntityBuilder; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -27,8 +29,6 @@ import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.logic.location.Location; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.rendering.logic.FloatingTextComponent; @@ -85,7 +85,7 @@ private void createOrUpdateNameTagFor(EntityRef entity, NameTagComponent nameTag nameTag = nameTagBuilder.build(); nameTagEntityToFloatingTextMap.put(entity, nameTag); - Location.attachChild(entity, nameTag, offset, new Quat4f(1, 0, 0, 0)); + Location.attachChild(entity, nameTag, offset, new Quaternionf()); } } From 6ba13559f9f791df4bf4349006d85c9879e4ef90 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 04:49:39 -0800 Subject: [PATCH 076/259] feat(JOML): migrate FloatingTextRenderer (#4344) --- .../rendering/logic/FloatingTextRenderer.java | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/logic/FloatingTextRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/FloatingTextRenderer.java index 90a54a73bb2..c7dc622b44f 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/FloatingTextRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/FloatingTextRenderer.java @@ -1,22 +1,12 @@ -/* - * Copyright 2016 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.logic; import com.google.common.collect.Maps; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.terasology.assets.management.AssetManager; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -28,8 +18,6 @@ import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.RenderSystem; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.nui.Color; import org.terasology.nui.HorizontalAlign; import org.terasology.registry.In; @@ -55,6 +43,7 @@ @RegisterSystem(RegisterMode.CLIENT) public class FloatingTextRenderer extends BaseComponentSystem implements RenderSystem { + private static final Logger logger = LoggerFactory.getLogger(FloatingTextRenderer.class); private static final int PIXEL_PER_METER = 250; @@ -83,21 +72,22 @@ public void initialise() { } private void render(Iterable floatingTextEntities) { - Vector3f cameraPosition = JomlUtil.from(camera.getPosition()); + Vector3fc cameraPosition = camera.getPosition(); for (EntityRef entity : floatingTextEntities) { + FloatingTextComponent floatingText = entity.getComponent(FloatingTextComponent.class); LocationComponent location = entity.getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { + + if (location == null) { + logger.warn("location component is not defined can't render text: {}", floatingText.text); continue; } - Vector3f worldPos = location.getWorldPosition(); - if (!worldProvider.isBlockRelevant(worldPos)) { + Vector3f worldPos = location.getWorldPosition(new Vector3f()); + if (!worldProvider.isBlockRelevant(worldPos) || !worldPos.isFinite()) { continue; } - FloatingTextComponent floatingText = entity.getComponent(FloatingTextComponent.class); - String[] linesOfText = floatingText.text.split("\n"); Color baseColor = floatingText.textColor; Color shadowColor = floatingText.textShadowColor; @@ -115,8 +105,8 @@ private void render(Iterable floatingTextEntities) { Map meshMap = entityMeshCache.get(entity); if (meshMap == null) { meshMap = meshBuilder - .createTextMesh(font, Arrays.asList(linesOfText), textWidth, HorizontalAlign.CENTER, baseColor, - shadowColor, underline); + .createTextMesh(font, Arrays.asList(linesOfText), textWidth, HorizontalAlign.CENTER, baseColor, + shadowColor, underline); entityMeshCache.put(entity, meshMap); } @@ -128,7 +118,7 @@ private void render(Iterable floatingTextEntities) { float scale = METER_PER_PIXEL * floatingText.scale; - glTranslated(worldPos.x - cameraPosition.x, worldPos.y - cameraPosition.y, worldPos.z - cameraPosition.z); + glTranslated(worldPos.x - cameraPosition.x(), worldPos.y - cameraPosition.y(), worldPos.z - cameraPosition.z()); OpenGLUtils.applyBillboardOrientation(); glScaled(scale, -scale, scale); glTranslated(-textWidth / 2.0, 0.0, 0.0); @@ -138,7 +128,7 @@ private void render(Iterable floatingTextEntities) { material.enable(); material.bindTextures(); material.setFloat4("croppingBoundaries", Float.MIN_VALUE, Float.MAX_VALUE, - Float.MIN_VALUE, Float.MAX_VALUE); + Float.MIN_VALUE, Float.MAX_VALUE); material.setFloat2("offset", 0.0f, 0.0f); material.setFloat("alpha", 1.0f); mesh.render(); From 59ccf892102bdba4fafa18379cc6d41c13f12441 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 05:10:02 -0800 Subject: [PATCH 077/259] feat(JOML): migrate LightComponent (#4345) --- .../java/org/terasology/rendering/logic/LightComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/rendering/logic/LightComponent.java b/engine/src/main/java/org/terasology/rendering/logic/LightComponent.java index 23301fefc75..7d022dba440 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/LightComponent.java +++ b/engine/src/main/java/org/terasology/rendering/logic/LightComponent.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.logic; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; import org.terasology.network.Replicate; import org.terasology.network.ReplicationCheck; import org.terasology.reflection.metadata.FieldMetadata; From 541a1e7068e5c2e4522b7b20eef88ffbd4aac103 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 05:29:21 -0800 Subject: [PATCH 078/259] feat(JOML): migrate BulletPhysics (#4348) --- .../physics/bullet/BulletPhysics.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java b/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java index c8643dcdd79..47db703c2b8 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java +++ b/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java @@ -324,7 +324,7 @@ public boolean updateRigidBody(EntityRef entity) { RigidBodyComponent rb = entity.getComponent(RigidBodyComponent.class); BulletRigidBody rigidBody = entityRigidBodies.get(entity); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { + if (location == null) { logger.warn("Updating rigid body of entity that has no " + "LocationComponent?! Nothing is done, except log this" + " warning instead. Entity: {}", entity); @@ -387,23 +387,25 @@ public boolean removeTrigger(EntityRef entity) { //TODO: update if detectGroups changed public boolean updateTrigger(EntityRef entity) { LocationComponent location = entity.getComponent(LocationComponent.class); - btPairCachingGhostObject triggerObj = entityTriggers.get(entity); - - if (location == null || Float.isNaN(location.getWorldPosition().x)) { + if (location == null) { logger.warn("Trying to update or create trigger of entity that has no LocationComponent?! Entity: {}", entity); return false; } + btPairCachingGhostObject triggerObj = entityTriggers.get(entity); + if (triggerObj != null) { float scale = location.getWorldScale(); if (Math.abs(triggerObj.getCollisionShape().getLocalScaling().x - scale) > SIMD_EPSILON) { discreteDynamicsWorld.removeCollisionObject(triggerObj); newTrigger(entity); } else { - Quaternionf worldRotation = JomlUtil.from(location.getWorldRotation()); - Vector3f worldPosition = JomlUtil.from(location.getWorldPosition()); - triggerObj.setWorldTransform(new Matrix4f().translationRotateScale(worldPosition,worldRotation,1.0f)); - -// triggerObj.setWorldTransform(new Matrix4f(worldRotation, worldPosition, 1.0f));//new Transform(new Matrix4f(worldRotation, worldPosition, 1.0f))); + Quaternionf worldRotation = location.getWorldRotation(new Quaternionf()); + Vector3f position = location.getWorldPosition(new Vector3f()); + if (!position.isFinite() || !worldRotation.isFinite()) { + logger.warn("Can't update Trigger entity with a non-finite position/rotation?! Entity: {}", entity); + return false; + } + triggerObj.setWorldTransform(new Matrix4f().translationRotateScale(position, worldRotation, 1.0f)); } return true; } else { @@ -493,7 +495,7 @@ private boolean newTrigger(EntityRef entity) { List detectGroups = Lists.newArrayList(trigger.detectGroups); CollisionGroup collisionGroup = trigger.collisionGroup; btPairCachingGhostObject triggerObj = createCollider( - JomlUtil.from(location.getWorldPosition()), + location.getWorldPosition(new Vector3f()), shape, collisionGroup.getFlag(), combineGroups(detectGroups), @@ -530,7 +532,7 @@ private CharacterCollider createCharacterCollider(EntityRef owner) { if (locComp == null || movementComp == null) { throw new IllegalArgumentException("Expected an entity with a Location component and CharacterMovementComponent."); } - Vector3f pos = new Vector3f(JomlUtil.from(locComp.getWorldPosition())); + Vector3f pos = locComp.getWorldPosition(new Vector3f()); final float worldScale = locComp.getWorldScale(); final float height = (movementComp.height - 2 * movementComp.radius) * worldScale; final float width = movementComp.radius * worldScale; @@ -563,7 +565,7 @@ private RigidBody newRigidBody(EntityRef entity) { collider.rb.setFriction(rigidBody.friction); collider.collidesWith = combineGroups(rigidBody.collidesWith); collider.setVelocity(rigidBody.velocity, rigidBody.angularVelocity); - collider.setTransform(JomlUtil.from(location.getWorldPosition()), JomlUtil.from(location.getWorldRotation())); + collider.setTransform(location.getWorldPosition(new Vector3f()), location.getWorldRotation(new Quaternionf())); updateKinematicSettings(rigidBody, collider); BulletRigidBody oldBody = entityRigidBodies.put(entity, collider); addRigidBody(collider, Lists.newArrayList(rigidBody.collisionGroup), rigidBody.collidesWith); @@ -1003,11 +1005,11 @@ public void setLocation(Vector3f loc) { public SweepCallback sweep(Vector3f startPos, Vector3f endPos, float allowedPenetration, float slopeFactor) { Matrix4f startTransform = new Matrix4f().translationRotateScale(startPos, new Quaternionf(), 1.0f); Matrix4f endTransform = new Matrix4f().translationRotateScale(endPos, new Quaternionf(), 1.0f); - BulletSweepCallback callback = new BulletSweepCallback(collider,startPos,slopeFactor); + BulletSweepCallback callback = new BulletSweepCallback(collider, startPos, slopeFactor); callback.setCollisionFilterGroup(collider.getBroadphaseHandle().getCollisionFilterGroup()); callback.setCollisionFilterMask(collider.getBroadphaseHandle().getCollisionFilterMask()); callback.setCollisionFilterGroup((short)(callback.getCollisionFilterGroup() & (~StandardCollisionGroup.SENSOR.getFlag()))); - collider.convexSweepTest((btConvexShape)(collider.getCollisionShape()),startTransform,endTransform,callback,allowedPenetration); + collider.convexSweepTest((btConvexShape)(collider.getCollisionShape()), startTransform, endTransform, callback, allowedPenetration); return callback; } } From 4157b464453536b856153b60b0acff02b8d2c5a8 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 05:46:48 -0800 Subject: [PATCH 079/259] feat(JOML): migrate EntityMotionState (#4355) --- .../terasology/physics/bullet/EntityMotionState.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/engine/src/main/java/org/terasology/physics/bullet/EntityMotionState.java b/engine/src/main/java/org/terasology/physics/bullet/EntityMotionState.java index fb566627de5..c6a97093af7 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/EntityMotionState.java +++ b/engine/src/main/java/org/terasology/physics/bullet/EntityMotionState.java @@ -24,7 +24,6 @@ import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; /** * This motion state is used to connect rigid body entities to their rigid body in the bullet physics engine. @@ -52,8 +51,8 @@ public class EntityMotionState extends btMotionState { @Override public void getWorldTransform(Matrix4f transform) { LocationComponent loc = entity.getComponent(LocationComponent.class); - transform.translationRotateScale(JomlUtil.from(loc.getWorldPosition()), - JomlUtil.from(loc.getWorldRotation()), loc.getWorldScale()); + transform.translationRotateScale(loc.getWorldPosition(position), + loc.getWorldRotation(rot), loc.getWorldScale()); } @Override @@ -63,9 +62,9 @@ public void setWorldTransform(Matrix4f transform) { rot.setFromNormalized(transform); rot.normalize(); transform.getTranslation(position); - loc.setWorldRotation(JomlUtil.from(rot)); - loc.setWorldPosition(JomlUtil.from(position)); + + loc.setWorldRotation(rot); + loc.setWorldPosition(position); } } - } From 7d72ed0bf8c257e4d81d8f62a9cc363ebbfc27c0 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 06:04:09 -0800 Subject: [PATCH 080/259] feat(JOML): migrate WorldProviderCore#isBlockRelevant (#4356) --- .../main/java/org/terasology/MapWorldProvider.java | 6 ++++++ .../terasology/testUtil/WorldProviderCoreStub.java | 6 ++++++ .../propagation/BetweenChunkPropagationTest.java | 6 ++++++ .../org/terasology/world/chunks/ChunkProvider.java | 7 +++++++ .../java/org/terasology/world/chunks/Chunks.java | 4 ++-- .../localChunkProvider/LocalChunkProvider.java | 6 ++++++ .../remoteChunkProvider/RemoteChunkProvider.java | 7 +++++++ .../internal/AbstractWorldProviderDecorator.java | 6 ++++++ .../terasology/world/internal/WorldProviderCore.java | 3 +++ .../world/internal/WorldProviderCoreImpl.java | 12 ++++++++++++ 10 files changed, 61 insertions(+), 2 deletions(-) diff --git a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java index 4a973f027ef..d569e45729d 100644 --- a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java +++ b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java @@ -26,6 +26,7 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; @@ -87,6 +88,11 @@ public boolean isRegionRelevant(Region3i region) { return false; } + @Override + public boolean isRegionRelevant(BlockRegionc region) { + return false; + } + @Override public Block setBlock(Vector3i pos, Block type) { return blocks.put(pos, type); diff --git a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java index bb6111b54ce..16830ab4adb 100644 --- a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java +++ b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java @@ -25,6 +25,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.internal.ChunkViewCore; import org.terasology.world.internal.WorldInfo; import org.terasology.world.internal.WorldProviderCore; @@ -103,6 +104,11 @@ public boolean isRegionRelevant(Region3i region) { return true; } + @Override + public boolean isRegionRelevant(BlockRegionc region) { + return false; + } + @Override public Block setBlock(Vector3i pos, Block type) { return this.setBlock(JomlUtil.from(pos), type); diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java index 5b54956c6cd..83a182902a9 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java @@ -16,6 +16,7 @@ package org.terasology.world.propagation; import com.google.common.collect.Maps; +import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.TerasologyTestingEnvironment; @@ -253,6 +254,11 @@ public boolean isChunkReady(Vector3i pos) { return false; } + @Override + public boolean isChunkReady(Vector3ic pos) { + return false; + } + @Override public Chunk getChunk(int x, int y, int z) { return getChunk(new Vector3i(x, y, z)); diff --git a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java index 36c6a68bd8b..ab1c62cd8ce 100644 --- a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java @@ -3,6 +3,7 @@ package org.terasology.world.chunks; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.geom.Vector3i; import org.terasology.world.internal.ChunkViewCore; @@ -69,6 +70,12 @@ public interface ChunkProvider { */ boolean isChunkReady(Vector3i pos); + /** + * @param pos + * @return Whether this chunk is available and ready for use + */ + boolean isChunkReady(Vector3ic pos); + /** * Returns the chunk at the given position if possible. * diff --git a/engine/src/main/java/org/terasology/world/chunks/Chunks.java b/engine/src/main/java/org/terasology/world/chunks/Chunks.java index fc0bd655903..6568071e76b 100644 --- a/engine/src/main/java/org/terasology/world/chunks/Chunks.java +++ b/engine/src/main/java/org/terasology/world/chunks/Chunks.java @@ -186,7 +186,7 @@ public static Vector3i toChunkPos(int x, int y, int z, int chunkX, int chunkY, i * @param dest will hold the result * @return dest */ - public static BlockRegion toChunkRegion(BlockRegion region, int chunkX, int chunkY, int chunkZ, BlockRegion dest) { + public static BlockRegion toChunkRegion(BlockRegionc region, int chunkX, int chunkY, int chunkZ, BlockRegion dest) { return dest. set(toChunkPos(region.minX(), chunkX), toChunkPos(region.minY(), chunkY), toChunkPos(region.minZ(), chunkZ), toChunkPos(region.maxX(), chunkX), toChunkPos(region.maxY(), chunkY), toChunkPos(region.maxZ(), chunkZ)); @@ -213,7 +213,7 @@ public static BlockRegion toChunkRegion(BlockRegion region, Vector3ic chunkPower * @param dest will hold the result * @return dest */ - public static BlockRegion toChunkRegion(BlockRegion region, BlockRegion dest) { + public static BlockRegion toChunkRegion(BlockRegionc region, BlockRegion dest) { return toChunkRegion(region, Chunks.POWER_X, Chunks.POWER_Y, Chunks.POWER_Z, dest); } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 0e35b4f5b02..edce50b20f2 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -10,6 +10,7 @@ import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.TShortObjectMap; import gnu.trove.map.hash.TShortObjectHashMap; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.Component; @@ -470,6 +471,11 @@ public boolean isChunkReady(Vector3i pos) { return isChunkReady(chunkCache.get(pos)); } + @Override + public boolean isChunkReady(Vector3ic pos) { + return isChunkReady(chunkCache.get(JomlUtil.from(pos))); + } + private boolean isChunkReady(Chunk chunk) { return chunk != null && chunk.isReady(); } diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 6a004f5edf3..cd76e32944d 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -6,6 +6,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Queues; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; @@ -149,6 +150,12 @@ public boolean isChunkReady(Vector3i pos) { return chunk != null && chunk.isReady(); } + @Override + public boolean isChunkReady(Vector3ic pos) { + Chunk chunk = chunkCache.get(JomlUtil.from(pos)); + return chunk != null && chunk.isReady(); + } + @Override public void dispose() { ChunkMonitor.fireChunkProviderDisposed(this); diff --git a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java index e1798eb02d1..38a914bdb2f 100644 --- a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java +++ b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java @@ -23,6 +23,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.time.WorldTime; import java.util.Collection; @@ -93,6 +94,11 @@ public boolean isRegionRelevant(Region3i region) { return base.isRegionRelevant(region); } + @Override + public boolean isRegionRelevant(BlockRegionc region) { + return base.isRegionRelevant(region); + } + @Override public Block setBlock(Vector3i pos, Block type) { return base.setBlock(pos, type); diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java index a618477e629..bd0aa3268bb 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java @@ -23,6 +23,7 @@ import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.time.WorldTime; import java.util.Collection; @@ -96,6 +97,8 @@ public interface WorldProviderCore { boolean isRegionRelevant(Region3i region); + boolean isRegionRelevant(BlockRegionc region); + /** * Places a block of a specific type at a given position * diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index 5507feaaca3..934040f54d7 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -21,8 +21,10 @@ import org.terasology.world.WorldComponent; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.CoreChunk; import org.terasology.world.chunks.LitChunk; import org.terasology.world.chunks.ManagedChunk; @@ -170,6 +172,16 @@ public boolean isRegionRelevant(Region3i region) { return true; } + @Override + public boolean isRegionRelevant(BlockRegionc region) { + for (Vector3ic chunkPos : Chunks.toChunkRegion(region, new BlockRegion(BlockRegion.INVALID))) { + if (!chunkProvider.isChunkReady(chunkPos)) { + return false; + } + } + return true; + } + @Override public Block setBlock(Vector3i worldPos, Block type) { return this.setBlock(JomlUtil.from(worldPos),type); From c9f5c0e461c6dddabb16fd56c18072b1619980c1 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 31 Dec 2020 06:46:37 -0800 Subject: [PATCH 081/259] feat: Add BlockAreaTypeHandler for serilization (#4338) Co-authored-by: Tobias Nett --- .../mathTypes/BlockAreaTypeHandlerTest.java | 72 +++++++++++++++++++ .../typeHandling/TypeHandlerLibraryImpl.java | 6 ++ .../mathTypes/BlockAreaTypeHandler.java | 52 ++++++++++++++ .../mathTypes/BlockAreacTypeHandler.java | 53 ++++++++++++++ .../mathTypes/RectanglefTypeHandler.java | 2 +- .../mathTypes/RectangleiTypeHandler.java | 2 +- 6 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandlerTest.java create mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandler.java create mode 100644 engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreacTypeHandler.java diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandlerTest.java new file mode 100644 index 00000000000..6c462bac0f6 --- /dev/null +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandlerTest.java @@ -0,0 +1,72 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.mathTypes; + +import org.junit.Assert; +import org.junit.jupiter.api.Test; +import org.terasology.ModuleEnvironmentTest; +import org.terasology.naming.Name; +import org.terasology.persistence.ModuleContext; +import org.terasology.persistence.serializers.GsonSerializer; +import org.terasology.persistence.serializers.ProtobufSerializer; +import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; +import org.terasology.reflection.TypeInfo; +import org.terasology.world.block.BlockArea; +import org.terasology.world.block.BlockAreac; + +import java.io.IOException; + +public class BlockAreaTypeHandlerTest extends ModuleEnvironmentTest { + + static class TestObject { + public BlockArea b1; + public BlockAreac b2; + } + + private TypeHandlerLibrary typeHandlerLibrary; + private ProtobufSerializer protobufSerializer; + private GsonSerializer gsonSerializer; + + @Override + public void setup() { + ModuleContext.setContext(moduleManager.getEnvironment().get(new Name("unittest"))); + + typeHandlerLibrary = TypeHandlerLibraryImpl.forModuleEnvironment(moduleManager, typeRegistry); + + protobufSerializer = new ProtobufSerializer(typeHandlerLibrary); + gsonSerializer = new GsonSerializer(typeHandlerLibrary); + } + + @Test + public void testGsonSerialization() throws IOException { + TestObject a = new TestObject(); + a.b1 = new BlockArea(-1, -1, 0, 0); + a.b2 = new BlockArea(0, 0, 1, 1); + + String data = gsonSerializer.toJson(a, new TypeInfo() { + }); + + TestObject o = gsonSerializer.fromJson(data, new TypeInfo() { + }); + Assert.assertEquals(o.b1, new BlockArea(-1, -1, 0, 0)); + Assert.assertEquals(o.b2, new BlockArea(0, 0, 1, 1)); + } + + @Test + public void testProtobufSerialize() throws IOException { + TestObject a = new TestObject(); + a.b1 = new BlockArea(-1, -1, 0, 0); + a.b2 = new BlockArea(0, 0, 1, 1); + + byte[] data = protobufSerializer.toBytes(a, new TypeInfo() { + }); + + TestObject o = protobufSerializer.fromBytes(data, new TypeInfo() { + }); + Assert.assertEquals(o.b1, new BlockArea(-1, -1, 0, 0)); + Assert.assertEquals(o.b2, new BlockArea(0, 0, 1, 1)); + } + +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java index 4ff9d829033..4cce55ef3e3 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java @@ -38,6 +38,8 @@ import org.terasology.persistence.typeHandling.extensionTypes.factories.TextureRegionAssetTypeHandlerFactory; import org.terasology.persistence.typeHandling.mathTypes.AABBfTypeHandler; import org.terasology.persistence.typeHandling.mathTypes.AABBiTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.BlockAreaTypeHandler; +import org.terasology.persistence.typeHandling.mathTypes.BlockAreacTypeHandler; import org.terasology.persistence.typeHandling.mathTypes.BlockRegionTypeHandler; import org.terasology.persistence.typeHandling.mathTypes.IntegerRangeHandler; import org.terasology.persistence.typeHandling.mathTypes.QuaternionfTypeHandler; @@ -66,6 +68,8 @@ import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; import org.terasology.reflection.TypeRegistry; import org.terasology.rendering.assets.texture.TextureRegion; +import org.terasology.world.block.BlockArea; +import org.terasology.world.block.BlockAreac; import org.terasology.world.block.BlockRegion; /** @@ -149,6 +153,8 @@ private static void populateWithDefaultHandlers(TypeHandlerLibrary serialization serializationLibrary.addTypeHandler(AABBi.class, new AABBiTypeHandler()); serializationLibrary.addTypeHandler(AABBf.class, new AABBfTypeHandler()); serializationLibrary.addTypeHandler(BlockRegion.class, new BlockRegionTypeHandler()); + serializationLibrary.addTypeHandler(BlockArea.class, new BlockAreaTypeHandler()); + serializationLibrary.addTypeHandler(BlockAreac.class, new BlockAreacTypeHandler()); serializationLibrary.addTypeHandler(Quaternionf.class, new QuaternionfTypeHandler()); serializationLibrary.addTypeHandler(Quaternionfc.class, new QuaternionfcTypeHandler()); diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandler.java new file mode 100644 index 00000000000..3de7edc7ec3 --- /dev/null +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreaTypeHandler.java @@ -0,0 +1,52 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.mathTypes; + +import com.google.common.collect.Maps; +import gnu.trove.list.TIntList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.PersistedDataArray; +import org.terasology.persistence.typeHandling.PersistedDataMap; +import org.terasology.persistence.typeHandling.PersistedDataSerializer; +import org.terasology.persistence.typeHandling.TypeHandler; +import org.terasology.world.block.BlockArea; + +import java.util.Map; +import java.util.Optional; + +public class BlockAreaTypeHandler extends TypeHandler { + private static final String MIN_FIELD = "min"; + private static final String MAX_FIELD = "max"; + private static final String SIZE_FIELD = "size"; + + @Override + protected PersistedData serializeNonNull(BlockArea value, PersistedDataSerializer serializer) { + Map map = Maps.newLinkedHashMap(); + map.put(MIN_FIELD, serializer.serialize(value.minX(), value.minY())); + map.put(MAX_FIELD, serializer.serialize(value.maxX(), value.maxY())); + return serializer.serialize(map); + } + + @Override + public Optional deserialize(PersistedData data) { + if (!data.isNull() && data.isValueMap()) { + PersistedDataMap map = data.getAsValueMap(); + + PersistedDataArray minDataArr = map.get(MIN_FIELD).getAsArray(); + TIntList minArr = minDataArr.getAsIntegerArray(); + if (map.has(SIZE_FIELD)) { + PersistedDataArray sizedataArray = map.get(SIZE_FIELD).getAsArray(); + TIntList sizeArr = sizedataArray.getAsIntegerArray(); + return Optional.of( + new BlockArea(minArr.get(0), minArr.get(1)) + .setSize(sizeArr.get(0), sizeArr.get(1))); + } + + PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); + TIntList maxArr = maxDataArr.getAsIntegerArray(); + return Optional.of(new BlockArea(minArr.get(0), minArr.get(1), maxArr.get(0), maxArr.get(1))); + } + return Optional.empty(); + } +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreacTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreacTypeHandler.java new file mode 100644 index 00000000000..5cad158978d --- /dev/null +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/BlockAreacTypeHandler.java @@ -0,0 +1,53 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.mathTypes; + +import com.google.common.collect.Maps; +import gnu.trove.list.TIntList; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.PersistedDataArray; +import org.terasology.persistence.typeHandling.PersistedDataMap; +import org.terasology.persistence.typeHandling.PersistedDataSerializer; +import org.terasology.persistence.typeHandling.TypeHandler; +import org.terasology.world.block.BlockArea; +import org.terasology.world.block.BlockAreac; + +import java.util.Map; +import java.util.Optional; + +public class BlockAreacTypeHandler extends TypeHandler { + private static final String MIN_FIELD = "min"; + private static final String MAX_FIELD = "max"; + private static final String SIZE_FIELD = "size"; + + @Override + protected PersistedData serializeNonNull(BlockAreac value, PersistedDataSerializer serializer) { + Map map = Maps.newLinkedHashMap(); + map.put(MIN_FIELD, serializer.serialize(value.minX(), value.minY())); + map.put(MAX_FIELD, serializer.serialize(value.maxX(), value.maxY())); + return serializer.serialize(map); + } + + @Override + public Optional deserialize(PersistedData data) { + if (!data.isNull() && data.isValueMap()) { + PersistedDataMap map = data.getAsValueMap(); + + PersistedDataArray minDataArr = map.get(MIN_FIELD).getAsArray(); + TIntList minArr = minDataArr.getAsIntegerArray(); + if (map.has(SIZE_FIELD)) { + PersistedDataArray sizedataArray = map.get(SIZE_FIELD).getAsArray(); + TIntList sizeArr = sizedataArray.getAsIntegerArray(); + return Optional.of( + new BlockArea(minArr.get(0), minArr.get(1)) + .setSize(sizeArr.get(0), sizeArr.get(1))); + } + + PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); + TIntList maxArr = maxDataArr.getAsIntegerArray(); + return Optional.of(new BlockArea(minArr.get(0), minArr.get(1), maxArr.get(0), maxArr.get(1))); + } + return Optional.empty(); + } +} diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java index 431d424a7b4..43c499ea0c0 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java @@ -33,7 +33,7 @@ public Optional deserialize(PersistedData data) { PersistedDataMap map = data.getAsValueMap(); PersistedDataArray minDataArr = map.get(MIN_FIELD).getAsArray(); - PersistedDataArray maxDataArr = map.get(MIN_FIELD).getAsArray(); + PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); TFloatList minArr = minDataArr.getAsFloatArray(); TFloatList maxArr = maxDataArr.getAsFloatArray(); diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java index 540859ee1b0..ef8ede84145 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java @@ -37,7 +37,7 @@ public Optional deserialize(PersistedData data) { PersistedDataMap map = data.getAsValueMap(); PersistedDataArray minDataArr = map.get(MIN_FIELD).getAsArray(); - PersistedDataArray maxDataArr = map.get(MIN_FIELD).getAsArray(); + PersistedDataArray maxDataArr = map.get(MAX_FIELD).getAsArray(); TIntList minArr = minDataArr.getAsIntegerArray(); TIntList maxArr = maxDataArr.getAsIntegerArray(); From 0cb61f659394eccca20f459286635df7fcb2d025 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 2 Jan 2021 08:28:05 -0800 Subject: [PATCH 082/259] feat(JOML): migrate SubSampledNoise for BlockArea (#4339) * feat(JOML): migrate SubSampleNoise for BlockArea * Update engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java Co-authored-by: Tobias Nett * correct docs and fix funcitons * chore: remove old implementation based on TeraMath types Co-authored-by: Tobias Nett Co-authored-by: jdrueckert --- .../utilities/procedural/SubSampledNoise.java | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java index 58d90ef676e..ff5c0ca50e3 100644 --- a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java +++ b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java @@ -22,6 +22,8 @@ import org.joml.Vector3i; import org.terasology.math.TeraMath; import org.terasology.math.geom.Rect2i; +import org.terasology.world.block.BlockArea; +import org.terasology.world.block.BlockAreac; import org.terasology.world.block.BlockRegion; /** @@ -65,19 +67,31 @@ public float noise(float x, float y) { return TeraMath.biLerp(q00, q10, q01, q11, xMod / sampleRate, yMod / sampleRate); } + /** + * + * @param region + * @return + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #noise(BlockAreac)}. + */ + @Deprecated public float[] noise(Rect2i region) { - Rect2i fullRegion = determineRequiredRegion(region); + return noise(new BlockArea(region.minX(), region.minY(), region.maxX(), region.maxY())); + } + + public float[] noise(BlockAreac area) { + BlockArea fullRegion = determineRequiredRegion(area); float[] keyData = getKeyValues(fullRegion); float[] fullData = mapExpand(keyData, fullRegion); - return getSubset(fullData, fullRegion, region); + return getSubset(fullData, fullRegion, area); } - private float[] getSubset(float[] fullData, Rect2i fullRegion, Rect2i subRegion) { - if (subRegion.sizeX() != fullRegion.sizeX() || subRegion.sizeY() != fullRegion.sizeY()) { - float[] result = new float[subRegion.sizeX() * subRegion.sizeY()]; + private float[] getSubset(float[] fullData, BlockAreac fullRegion, BlockAreac subRegion) { + if (subRegion.getSizeX() != fullRegion.getSizeX() || subRegion.getSizeY() != fullRegion.getSizeY()) { + float[] result = new float[subRegion.getSizeX() * subRegion.getSizeY()]; Vector2i offset = new Vector2i(subRegion.minX() - fullRegion.minX(), subRegion.minY() - fullRegion.minY()); - for (int y = 0; y < subRegion.sizeY(); ++y) { - System.arraycopy(fullData, offset.x() + fullRegion.sizeX() * (y + offset.y()), result, subRegion.sizeX() * y, subRegion.sizeX()); + for (int y = 0; y < subRegion.getSizeY(); ++y) { + System.arraycopy(fullData, offset.x() + fullRegion.getSizeX() * (y + offset.y()), result, subRegion.getSizeX() * y, subRegion.getSizeX()); } return result; } else { @@ -85,10 +99,10 @@ private float[] getSubset(float[] fullData, Rect2i fullRegion, Rect2i subRegion) } } - private float[] mapExpand(float[] keyData, Rect2i fullRegion) { - float[] fullData = new float[fullRegion.sizeX() * fullRegion.sizeY()]; - int samplesX = fullRegion.sizeX() / sampleRate + 1; - int samplesY = fullRegion.sizeY() / sampleRate + 1; + private float[] mapExpand(float[] keyData, BlockAreac fullRegion) { + float[] fullData = new float[fullRegion.getSizeX() * fullRegion.getSizeY()]; + int samplesX = fullRegion.getSizeX() / sampleRate + 1; + int samplesY = fullRegion.getSizeY() / sampleRate + 1; for (int y = 0; y < samplesY - 1; y++) { for (int x = 0; x < samplesX - 1; x++) { float q11 = keyData[x + y * samplesX]; @@ -97,8 +111,8 @@ private float[] mapExpand(float[] keyData, Rect2i fullRegion) { float q22 = keyData[(x + 1) + (y + 1) * samplesX]; for (int innerY = 0; innerY < sampleRate; ++innerY) { for (int innerX = 0; innerX < sampleRate; ++innerX) { - fullData[x * sampleRate + innerX + fullRegion.sizeX() * (y * sampleRate + innerY)] = - TeraMath.biLerp(q11, q21, q12, q22, (float) innerX / sampleRate, (float) innerY / sampleRate); + fullData[x * sampleRate + innerX + fullRegion.getSizeX() * (y * sampleRate + innerY)] = + TeraMath.biLerp(q11, q21, q12, q22, (float) innerX / sampleRate, (float) innerY / sampleRate); } } } @@ -106,9 +120,9 @@ private float[] mapExpand(float[] keyData, Rect2i fullRegion) { return fullData; } - private float[] getKeyValues(Rect2i fullRegion) { - int xDim = fullRegion.sizeX() / sampleRate + 1; - int yDim = fullRegion.sizeY() / sampleRate + 1; + private float[] getKeyValues(BlockAreac fullRegion) { + int xDim = fullRegion.getSizeX() / sampleRate + 1; + int yDim = fullRegion.getSizeY() / sampleRate + 1; float[] fullData = new float[xDim * yDim]; for (int y = 0; y < yDim; y++) { for (int x = 0; x < xDim; x++) { @@ -121,15 +135,14 @@ private float[] getKeyValues(Rect2i fullRegion) { return fullData; } - private Rect2i determineRequiredRegion(Rect2i region) { + private BlockArea determineRequiredRegion(BlockAreac region) { int newMinX = region.minX() - IntMath.mod(region.minX(), sampleRate); int newMinY = region.minY() - IntMath.mod(region.minY(), sampleRate); int newMaxX = region.maxX() + 4 - IntMath.mod(region.maxX(), sampleRate) - 1; int newMaxY = region.maxY() + 4 - IntMath.mod(region.maxY(), sampleRate) - 1; - return Rect2i.createFromMinAndMax(newMinX, newMinY, newMaxX, newMaxY); + return new BlockArea(newMinX, newMinY, newMaxX, newMaxY); } - @Override public float noise(float x, float y, float z) { float xMod = TeraMath.modulus(x, sampleRate); @@ -177,6 +190,7 @@ private float[] getSubset(float[] fullData, BlockRegion fullRegion, BlockRegion } } + private float[] mapExpand(float[] keyData, BlockRegion fullRegion) { float[] fullData = new float[fullRegion.volume()]; int samplesX = fullRegion.getSizeX() / sampleRate + 1; From d1476d4442bcc3b39d42d1b9b2309a38ce0d0076 Mon Sep 17 00:00:00 2001 From: Rasmus Praestholm Date: Sat, 2 Jan 2021 13:08:26 -0600 Subject: [PATCH 083/259] chore: Couple minor tweaks - logic hardening and memory (#4365) * chore: harden a behavior tree piece of logic that seems to crash occasionally, leave todo to capture it for telemetry as well * feat: Increase default memory max when running the game from Gradle (beyond what a 32-bit JVM can supply!) --- .../java/org/terasology/logic/behavior/BehaviorSystem.java | 6 ++++++ facades/PC/build.gradle.kts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/logic/behavior/BehaviorSystem.java b/engine/src/main/java/org/terasology/logic/behavior/BehaviorSystem.java index de6c5892532..abf1b210723 100644 --- a/engine/src/main/java/org/terasology/logic/behavior/BehaviorSystem.java +++ b/engine/src/main/java/org/terasology/logic/behavior/BehaviorSystem.java @@ -102,6 +102,12 @@ public void update(float delta) { Iterable entities = entityManager.getEntitiesWith(BehaviorComponent.class); for (EntityRef entity : entities) { BehaviorComponent behaviorComponent = entity.getComponent(BehaviorComponent.class); + // NPE observed in the past, suspected to be about loss of behavior state. Hopefully one skip is OK then resume next tick? + // TODO: Highlight this log entry to the telemetry system to gather better data over time + if (behaviorComponent.interpreter == null) { + logger.warn("Found a null interpreter during tick updates, skipping for entity {}", entity); + continue; + } behaviorComponent.interpreter.tick(delta); } } diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 36b1395b473..82cb15fe70f 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -127,7 +127,7 @@ val commonConfigure : JavaExec.()-> Unit = { classpath(sourceSets["main"].runtimeClasspath) args("-homedir") - jvmArgs("-Xmx1536m") + jvmArgs("-Xmx3072m") if (isMacOS()) { args("-noSplash") From f383cb13f6c9ecf972c1e3532e24c1aadcb5b08c Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 2 Jan 2021 16:00:43 -0800 Subject: [PATCH 084/259] chore (build): the dependency on modules is for local dev builds --- facades/PC/build.gradle.kts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 8c2259d9b03..29d6b33a659 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 // The PC facade is responsible for the primary distribution - a plain Java application runnable on PCs @@ -93,6 +93,9 @@ dependencies { // TODO: Consider whether we can move the CR dependency back here from the engine, where it is referenced from the main menu implementation(group = "org.terasology.crashreporter", name = "cr-terasology", version = "4.1.0") + // Make sure any local module builds are up-to-date and have their dependencies by declaring + // a runtime dependency on whatever the `:modules` subproject declares. + // This won't add anything if there are no modules checked out. runtimeOnly(platform(project(":modules"))) } From 32cc29a9a18156aa7199e87c3d99d1ca1d33e306 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 3 Jan 2021 04:15:04 -0800 Subject: [PATCH 085/259] feat(JOML): migrate Direction (#4363) --- .../java/org/terasology/math/Direction.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/engine/src/main/java/org/terasology/math/Direction.java b/engine/src/main/java/org/terasology/math/Direction.java index 946294809af..427ac459e64 100644 --- a/engine/src/main/java/org/terasology/math/Direction.java +++ b/engine/src/main/java/org/terasology/math/Direction.java @@ -1,22 +1,9 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.math; import com.google.common.collect.Maps; +import org.joml.Math; import org.joml.Vector3fc; import org.joml.Vector3ic; import org.terasology.math.geom.Vector3f; @@ -65,20 +52,31 @@ public enum Direction { } public static Direction inDirection(int x, int y, int z) { - if (TeraMath.fastAbs(x) > TeraMath.fastAbs(y)) { - if (TeraMath.fastAbs(x) > TeraMath.fastAbs(z)) { + if (Math.abs(x) > Math.abs(y)) { + if (Math.abs(x) > Math.abs(z)) { return (x > 0) ? LEFT : RIGHT; } - } else if (TeraMath.fastAbs(y) > TeraMath.fastAbs(z)) { + } else if (Math.abs(y) > Math.abs(z)) { return (y > 0) ? UP : DOWN; } return (z > 0) ? FORWARD : BACKWARD; } + /** + * @param dir + * @return + * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation + * {@link #inDirection(Vector3fc)}. + */ + @Deprecated public static Direction inDirection(Vector3f dir) { return inDirection(dir.x, dir.y, dir.z); } + public static Direction inDirection(Vector3fc dir) { + return inDirection(dir.x(), dir.y(), dir.z()); + } + public Side toSide() { return CONVERSION_MAP.get(this); } @@ -92,11 +90,11 @@ public Side toSide() { * @return Side enum with the appropriate direction */ public static Direction inDirection(float x, float y, float z) { - if (TeraMath.fastAbs(x) > TeraMath.fastAbs(y)) { - if (TeraMath.fastAbs(x) > TeraMath.fastAbs(z)) { + if (Math.abs(x) > Math.abs(y)) { + if (Math.abs(x) > Math.abs(z)) { return (x > 0) ? LEFT : RIGHT; } - } else if (TeraMath.fastAbs(y) > TeraMath.fastAbs(z)) { + } else if (Math.abs(y) > Math.abs(z)) { return (y > 0) ? UP : DOWN; } return (z > 0) ? FORWARD : BACKWARD; @@ -110,7 +108,7 @@ public static Direction inDirection(float x, float y, float z) { * @return Side enum with the appropriate direction */ public static Direction inHorizontalDirection(float x, float z) { - if (TeraMath.fastAbs(x) > TeraMath.fastAbs(z)) { + if (Math.abs(x) > Math.abs(z)) { return (x > 0) ? LEFT : RIGHT; } return (z > 0) ? FORWARD : BACKWARD; @@ -141,6 +139,7 @@ public Vector3fc asVector3f() { * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation * {@link #asVector3i()}. */ + @Deprecated public Vector3i getVector3i() { return new Vector3i(vector3iDir); } @@ -150,6 +149,7 @@ public Vector3i getVector3i() { * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation * {@link #asVector3f()} */ + @Deprecated public Vector3f getVector3f() { return new Vector3f(vector3fDir); } From 2e7ab128ef686d2f05ae01d95485b1f6fb4467da Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Sun, 3 Jan 2021 19:27:20 +0000 Subject: [PATCH 086/259] fix: Move the final stage of chunk loading back to the main thread. --- .../LocalChunkProviderTest.java | 2 +- .../BetweenChunkPropagationTest.java | 8 +---- .../loadProcesses/AwaitCharacterSpawn.java | 3 +- .../renderer/HeadlessWorldRenderer.java | 3 +- .../rendering/world/RenderableWorldImpl.java | 11 ++----- .../world/chunks/ChunkProvider.java | 7 +---- .../LocalChunkProvider.java | 16 +++++----- .../RemoteChunkProvider.java | 30 +++++++++---------- 8 files changed, 31 insertions(+), 49 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index 66f1bfefac5..ecd72895b94 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -256,7 +256,7 @@ void testUnloadChunkAndDeactivationBlock() throws InterruptedException, TimeoutE .filter((e) -> e instanceof BeforeDeactivateBlocks) .map((e) -> (BeforeDeactivateBlocks) e) .findFirst().isPresent()) { - chunkProvider.beginUpdate(); + chunkProvider.update(); blockEventCaptor = ArgumentCaptor.forClass(Event.class); verify(blockAtBlockManager.getEntity(), atLeast(1)).send(blockEventCaptor.capture()); diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java index 83a182902a9..5463a9b10df 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java @@ -39,7 +39,6 @@ import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; -import org.terasology.world.chunks.ChunkRegionListener; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; import org.terasology.world.internal.ChunkViewCore; @@ -240,12 +239,7 @@ public Collection getAllChunks() { } @Override - public void completeUpdate() { - // do nothing - } - - @Override - public void beginUpdate() { + public void update() { // do nothing } diff --git a/engine/src/main/java/org/terasology/engine/modes/loadProcesses/AwaitCharacterSpawn.java b/engine/src/main/java/org/terasology/engine/modes/loadProcesses/AwaitCharacterSpawn.java index 48630ab6dca..0842f38ea8e 100644 --- a/engine/src/main/java/org/terasology/engine/modes/loadProcesses/AwaitCharacterSpawn.java +++ b/engine/src/main/java/org/terasology/engine/modes/loadProcesses/AwaitCharacterSpawn.java @@ -55,8 +55,7 @@ public boolean step() { client.character.send(new AwaitedLocalCharacterSpawnEvent()); return true; } else { - chunkProvider.completeUpdate(); - chunkProvider.beginUpdate(); + chunkProvider.update(); } return false; } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java index e8e98fd9180..3ba72fa9d73 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java @@ -101,8 +101,7 @@ public void update(float delta) { // Free unused space PerformanceMonitor.startActivity("Update Chunk Cache"); - chunkProvider.completeUpdate(); - chunkProvider.beginUpdate(); + chunkProvider.update(); PerformanceMonitor.endActivity(); PerformanceMonitor.startActivity("Update Close Chunks"); diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index 0bc485a8a91..1bccf7ef7b6 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -137,8 +137,7 @@ public void onChunkUnloaded(Vector3ic chunkCoordinates) { public boolean pregenerateChunks() { boolean pregenerationIsComplete = true; - chunkProvider.completeUpdate(); - chunkProvider.beginUpdate(); + chunkProvider.update(); RenderableChunk chunk; ChunkMesh newMesh; @@ -172,16 +171,12 @@ public boolean pregenerateChunks() { @Override public void update() { - PerformanceMonitor.startActivity("Complete chunk update"); - chunkProvider.completeUpdate(); - PerformanceMonitor.endActivity(); - PerformanceMonitor.startActivity("Update Lighting"); worldProvider.processPropagation(); PerformanceMonitor.endActivity(); - PerformanceMonitor.startActivity("Begin chunk update"); - chunkProvider.beginUpdate(); + PerformanceMonitor.startActivity("Chunk update"); + chunkProvider.update(); PerformanceMonitor.endActivity(); PerformanceMonitor.startActivity("Update Close Chunks"); diff --git a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java index ab1c62cd8ce..29d991cb864 100644 --- a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java @@ -43,15 +43,10 @@ public interface ChunkProvider { */ void setWorldEntity(EntityRef entity); - /** - * Finish adding any pending chunks - */ - void completeUpdate(); - /** * Updates the near cache based on the movement of the caching entities */ - void beginUpdate(); + void update(); /** * @param pos the chunk coordinates diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index edce50b20f2..7ca09258282 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -92,6 +92,7 @@ public class LocalChunkProvider implements ChunkProvider { private static final Logger logger = LoggerFactory.getLogger(LocalChunkProvider.class); private static final int UNLOAD_PER_FRAME = 64; private final EntityManager entityManager; + private final BlockingQueue readyChunks = Queues.newLinkedBlockingQueue(); private final BlockingQueue> deactivateBlocksQueue = Queues.newLinkedBlockingQueue(); private final Map chunkCache; @@ -188,11 +189,6 @@ public void setWorldEntity(EntityRef worldEntity) { } - @Override - public void completeUpdate() { - //TODO remove this. - } - private void processReadyChunk(final Chunk chunk) { if (chunkCache.get(chunk.getPosition()) != null) { return; // TODO move it in pipeline; @@ -262,9 +258,13 @@ private void generateQueuedEntities(EntityStore store) { } @Override - public void beginUpdate() { + public void update() { deactivateBlocks(); checkForUnload(); + Chunk chunk; + while ((chunk = readyChunks.poll()) != null) { + processReadyChunk(chunk); + } } private void deactivateBlocks() { @@ -454,7 +454,7 @@ public void purgeWorld() { .map(org.joml.Vector3i::new) .collect(Collectors.toSet()) )) - .addStage(ChunkTaskProvider.create("Chunk ready", this::processReadyChunk)); + .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); unloadRequestTaskMaster = TaskMaster.createFIFOTaskMaster("Chunk-Unloader", 8); ChunkMonitor.fireChunkProviderInitialized(this); @@ -497,6 +497,6 @@ public void setRelevanceSystem(RelevanceSystem relevanceSystem) { .map(org.joml.Vector3i::new) .collect(Collectors.toCollection(Sets::newLinkedHashSet)) )) - .addStage(ChunkTaskProvider.create("Chunk ready", this::processReadyChunk)); + .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index cd76e32944d..422e403b7c6 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -55,6 +55,7 @@ public class RemoteChunkProvider implements ChunkProvider { private static final Logger logger = LoggerFactory.getLogger(RemoteChunkProvider.class); + private final BlockingQueue readyChunks = Queues.newLinkedBlockingQueue(); private final BlockingQueue invalidateChunks = Queues.newLinkedBlockingQueue(); private final Map chunkCache = Maps.newHashMap(); private final BlockManager blockManager; @@ -80,15 +81,7 @@ public RemoteChunkProvider(BlockManager blockManager, LocalPlayer localPlayer) { .map(org.joml.Vector3i::new) .collect(Collectors.toSet()) )) - .addStage(ChunkTaskProvider.create("", chunk -> { - Chunk oldChunk = chunkCache.put(chunk.getPosition(), chunk); - if (oldChunk != null) { - oldChunk.dispose(); - } - chunk.markReady(); - listener.onChunkReady(chunk.getPosition()); - worldEntity.send(new OnChunkLoaded(chunk.getPosition())); - })); + .addStage(ChunkTaskProvider.create("", readyChunks::add)); ChunkMonitor.fireChunkProviderInitialized(this); } @@ -107,15 +100,22 @@ public void invalidateChunks(Vector3i pos) { } @Override - public void completeUpdate() { - //TODO remove this - } - - @Override - public void beginUpdate() { + public void update() { if (listener != null) { checkForUnload(); } + Chunk chunk; + while ((chunk = readyChunks.poll()) != null) { + Chunk oldChunk = chunkCache.put(chunk.getPosition(), chunk); + if (oldChunk != null) { + oldChunk.dispose(); + } + chunk.markReady(); + if (listener != null) { + listener.onChunkReady(chunk.getPosition()); + } + worldEntity.send(new OnChunkLoaded(chunk.getPosition())); + } } private void checkForUnload() { From 2f785e0590ce4a50fc9f0e27190fee3aca6d65e0 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Sun, 3 Jan 2021 20:25:28 +0000 Subject: [PATCH 087/259] Fix: LocalChunkProviderTest (#4371) --- .../chunks/localChunkProvider/LocalChunkProviderTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index ecd72895b94..bed4d0e816b 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -111,6 +111,7 @@ private Future requestCreatingOrLoadingArea(Vector3i chunkPosition) { void testGenerateSingleChunk() throws InterruptedException, ExecutionException, TimeoutException { Vector3i chunkPosition = new Vector3i(0, 0, 0); requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); + chunkProvider.update(); final ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); verify(worldEntity, atLeast(2)).send(eventArgumentCaptor.capture()); @@ -139,6 +140,7 @@ void testGenerateSingleChunkWithBlockLifeCycle() throws InterruptedException, Ex blockAtBlockManager.setLifecycleEventsRequired(true); blockAtBlockManager.setEntity(mock(EntityRef.class)); requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); + chunkProvider.update(); final ArgumentCaptor worldEventCaptor = ArgumentCaptor.forClass(Event.class); verify(worldEntity, atLeast(2)).send(worldEventCaptor.capture()); @@ -180,6 +182,7 @@ void testLoadSingleChunk() throws InterruptedException, ExecutionException, Time storageManager.add(chunk); requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); + chunkProvider.update(); Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), "Entities must be restored by loading"); @@ -204,6 +207,7 @@ void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, Execut blockAtBlockManager.setEntity(mock(EntityRef.class)); requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); + chunkProvider.update(); Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), "Entities must be restored by loading"); From 05ef54d62635a42b0dcb4a1ac5a3088c165e3db7 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 4 Jan 2021 04:47:29 -0800 Subject: [PATCH 088/259] feat: add Chunks#toRelative(x,y,z,dest) (#4373) --- .../java/org/terasology/world/chunks/Chunks.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/Chunks.java b/engine/src/main/java/org/terasology/world/chunks/Chunks.java index 6568071e76b..fb7f465f1f3 100644 --- a/engine/src/main/java/org/terasology/world/chunks/Chunks.java +++ b/engine/src/main/java/org/terasology/world/chunks/Chunks.java @@ -271,7 +271,6 @@ public static Vector3i toRelative(Vector3ic worldPos, Vector3i dest) { /** * the relative position in the nearest chunk from the (0,0,0) corner. - * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). * * @param x the x world position * @param y the y world position @@ -284,7 +283,20 @@ public static Vector3i toRelative(int x, int y, int z, Vector3ic chunkFilterSize return dest.set(toRelative(x, chunkFilterSize.x()), toRelative(y, chunkFilterSize.y()), toRelative(z, chunkFilterSize.z())); } - + /** + * the relative position in the nearest chunk from the (0,0,0) corner. + * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). + * + * @param x the x world position + * @param y the y world position + * @param z the z world position + * @param dest will hold the result + * @return dest + */ + public static Vector3i toRelative(int x, int y, int z, Vector3i dest) { + return dest.set(toRelative(x, INNER_CHUNK_POS_FILTER.x()), toRelative(y, INNER_CHUNK_POS_FILTER.y()), toRelative(z, INNER_CHUNK_POS_FILTER.z())); + } + /** * Works out whether the given block resides inside the given chunk. *

From 53704509283f96990294f9a6228d576602089925 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 4 Jan 2021 10:35:50 -0800 Subject: [PATCH 089/259] fix: remove reflection for gson deserilization in GsonTypeHandlerAdapter (#4370) --- .../gson/GsonTypeHandlerAdapter.java | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerAdapter.java b/engine/src/main/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerAdapter.java index b720eb57d40..6261d471da2 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerAdapter.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/gson/GsonTypeHandlerAdapter.java @@ -20,18 +20,13 @@ package org.terasology.persistence.typeHandling.gson; import com.google.gson.Gson; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; import com.google.gson.TypeAdapter; import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import org.terasology.persistence.typeHandling.TypeHandler; -import org.terasology.utilities.ReflectionUtil; import java.io.IOException; @@ -48,24 +43,10 @@ public final class GsonTypeHandlerAdapter extends TypeAdapter { private final TypeHandler typeHandler; - private final JsonSerializer serializer; - private final JsonDeserializer deserializer; - private final Gson gson; - private final TypeToken typeToken; GsonTypeHandlerAdapter(TypeHandler typeHandler, Gson gson, TypeToken typeToken) { this.typeHandler = typeHandler; - - this.serializer = (src, typeOfSrc, context) -> - ((GsonPersistedData) typeHandler.serialize(src, new GsonPersistedDataSerializer())) - .getElement(); - - this.deserializer = (json, typeOfT, context) -> - typeHandler.deserializeOrNull(new GsonPersistedData(json)); - - this.gson = gson; - this.typeToken = typeToken; } @Override @@ -74,8 +55,7 @@ public T read(JsonReader in) throws IOException { if (value.isJsonNull()) { return null; } - - return deserializer.deserialize(value, typeToken.getType(), (JsonDeserializationContext) ReflectionUtil.readField(gson, "deserializationContext")); + return this.typeHandler.deserializeOrNull(new GsonPersistedData(value)); } @Override @@ -84,7 +64,7 @@ public void write(JsonWriter out, T value) throws IOException { out.nullValue(); return; } - JsonElement tree = serializer.serialize(value, typeToken.getType(), (JsonSerializationContext) ReflectionUtil.readField(gson, "serializationContext")); + JsonElement tree = ((GsonPersistedData) typeHandler.serialize(value, new GsonPersistedDataSerializer())).getElement(); Streams.write(tree, out); } } From e3628a64f0be1b31a25ceee3f86d3138edaf1c17 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 4 Jan 2021 11:00:19 -0800 Subject: [PATCH 090/259] feat(JOML): migrate VisualCharacterSystem (#4360) --- .../characters/VisualCharacterSystem.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/characters/VisualCharacterSystem.java b/engine/src/main/java/org/terasology/logic/characters/VisualCharacterSystem.java index de10b432984..99b4621cef4 100644 --- a/engine/src/main/java/org/terasology/logic/characters/VisualCharacterSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/VisualCharacterSystem.java @@ -15,6 +15,8 @@ */ package org.terasology.logic.characters; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.assets.management.AssetManager; import org.terasology.engine.modes.loadProcesses.AwaitedLocalCharacterSpawnEvent; import org.terasology.entitySystem.entity.EntityBuilder; @@ -32,8 +34,6 @@ import org.terasology.logic.location.Location; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; /** @@ -85,7 +85,7 @@ void createVisualCharacterIfNotOwnCharacter(EntityRef characterEntity, VisualCha characterEntity.send(event); EntityBuilder entityBuilder = event.getVisualCharacterBuilder(); EntityRef visualCharacterEntity = createAndAttachVisualEntityStrategy.createAndAttachVisualEntity(entityBuilder, - characterEntity); + characterEntity); visualCharacterComponent.visualCharacter = visualCharacterEntity; characterEntity.saveComponent(visualCharacterComponent); @@ -97,7 +97,7 @@ private EntityRef createAndAttachVisualEntity(EntityBuilder entityBuilder, Entit entityBuilder.addOrSaveComponent(new LocationComponent()); EntityRef visualCharacterEntity = entityBuilder.build(); - Location.attachChild(characterEntity, visualCharacterEntity, new Vector3f(), new Quat4f(0, 0, 0, 1)); + Location.attachChild(characterEntity, visualCharacterEntity, new Vector3f(), new Quaternionf()); return visualCharacterEntity; } @@ -106,15 +106,15 @@ interface VisualEntityBuildAndAttachStrategy { } /** - * Handles the local character spawn event by doing the work that had to be delayed till then: - * The CreateVisualCharacterEvent events that could not be sent previously will be sent. - * (They could not be sent earlier as we need to know if the character belongs to the local player or not - * which can't be determined if the created/loaded character has not been linked to the player yet) + * Handles the local character spawn event by doing the work that had to be delayed till then: The + * CreateVisualCharacterEvent events that could not be sent previously will be sent. (They could not be sent earlier + * as we need to know if the character belongs to the local player or not which can't be determined if the + * created/loaded character has not been linked to the player yet) */ @ReceiveEvent public void onAwaitedLocalCharacterSpawnEvent(AwaitedLocalCharacterSpawnEvent event, EntityRef entity) { awaitedLocalCharacterSpawn = true; - for (EntityRef character: entityManager.getEntitiesWith(VisualCharacterComponent.class)) { + for (EntityRef character : entityManager.getEntitiesWith(VisualCharacterComponent.class)) { createVisualCharacterIfNotOwnCharacter(character, character.getComponent(VisualCharacterComponent.class)); } } From 19c233b290a430577b0358349c7c255d6b07afb8 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 4 Jan 2021 11:22:14 -0800 Subject: [PATCH 091/259] feat(JOML): migrate DebugOverlay (#4359) --- .../layers/ingame/metrics/DebugOverlay.java | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/nui/layers/ingame/metrics/DebugOverlay.java b/engine/src/main/java/org/terasology/rendering/nui/layers/ingame/metrics/DebugOverlay.java index 496ec939336..cc41c53686d 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/layers/ingame/metrics/DebugOverlay.java +++ b/engine/src/main/java/org/terasology/rendering/nui/layers/ingame/metrics/DebugOverlay.java @@ -15,22 +15,22 @@ */ package org.terasology.rendering.nui.layers.ingame.metrics; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.terasology.config.Config; import org.terasology.engine.Time; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.input.cameraTarget.CameraTargetSystem; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.ChunkMath; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; +import org.terasology.nui.databinding.ReadOnlyBinding; +import org.terasology.nui.widgets.UILabel; import org.terasology.persistence.StorageManager; import org.terasology.registry.In; import org.terasology.rendering.nui.CoreScreenLayer; -import org.terasology.nui.databinding.ReadOnlyBinding; -import org.terasology.nui.widgets.UILabel; import org.terasology.rendering.primitives.ChunkTessellator; import org.terasology.world.WorldProvider; +import org.terasology.world.chunks.Chunks; import java.util.Locale; @@ -64,11 +64,10 @@ public class DebugOverlay extends CoreScreenLayer { @In private DebugMetricsSystem debugMetricsSystem; - private UILabel metricsLabel; - @In private StorageManager storageManager; + private UILabel metricsLabel; @Override public void initialise() { @@ -86,7 +85,7 @@ public Boolean get() { public String get() { double memoryUsage = ((double) Runtime.getRuntime().totalMemory() - (double) Runtime.getRuntime().freeMemory()) / 1048576.0; return String.format("FPS: %.2f, Memory Usage: %.2f MB, Total Memory: %.2f MB, Max Memory: %.2f MB", - time.getFps(), memoryUsage, Runtime.getRuntime().totalMemory() / 1048576.0, Runtime.getRuntime().maxMemory() / 1048576.0); + time.getFps(), memoryUsage, Runtime.getRuntime().totalMemory() / 1048576.0, Runtime.getRuntime().maxMemory() / 1048576.0); } }); } @@ -106,14 +105,14 @@ public String get() { debugLine3.bindText(new ReadOnlyBinding() { @Override public String get() { - Vector3f pos = localPlayer.getPosition(); - Vector3i chunkPos = ChunkMath.calcChunkPos((int) pos.x, (int) pos.y, (int) pos.z); - Vector3f rotation = localPlayer.getViewDirection(); - Vector3f cameraPos = localPlayer.getViewPosition(); + Vector3f pos = localPlayer.getPosition(new Vector3f()); + Vector3i chunkPos = Chunks.toChunkPos(pos, new Vector3i()); + Vector3f rotation = localPlayer.getViewDirection(new Vector3f()); + Vector3f cameraPos = localPlayer.getViewPosition(new Vector3f()); return String.format(Locale.US, "Position: (%.2f, %.2f, %.2f), Chunk (%d, %d, %d), Eye (%.2f, %.2f, %.2f), Rot (%.2f, %.2f, %.2f)", pos.x, pos.y, pos.z, - chunkPos.x, chunkPos.y, chunkPos.z, - cameraPos.x, cameraPos.y, cameraPos.z, - rotation.x, rotation.y, rotation.z); + chunkPos.x, chunkPos.y, chunkPos.z, + cameraPos.x, cameraPos.y, cameraPos.z, + rotation.x, rotation.y, rotation.z); } }); } @@ -124,9 +123,9 @@ public String get() { @Override public String get() { return String.format("Total VUs: %s, World Time: %.3f, Time Dilation: %.1f", - ChunkTessellator.getVertexArrayUpdateCount(), - worldProvider.getTime().getDays() - 0.0005f, // use floor instead of rounding up - time.getGameTimeDilation()); + ChunkTessellator.getVertexArrayUpdateCount(), + worldProvider.getTime().getDays() - 0.0005f, // use floor instead of rounding up + time.getGameTimeDilation()); } }); } @@ -151,12 +150,12 @@ public String get() { } }); saveStatusLabel.bindVisible( - new ReadOnlyBinding() { - @Override - public Boolean get() { - return storageManager.isSaving(); - } + new ReadOnlyBinding() { + @Override + public Boolean get() { + return storageManager.isSaving(); } + } ); } @@ -170,12 +169,12 @@ public String get() { } }); wireframeMode.bindVisible( - new ReadOnlyBinding() { - @Override - public Boolean get() { - return config.getRendering().getDebug().isWireframe(); - } + new ReadOnlyBinding() { + @Override + public Boolean get() { + return config.getRendering().getDebug().isWireframe(); } + } ); } @@ -189,12 +188,12 @@ public String get() { } }); chunkRenderMode.bindVisible( - new ReadOnlyBinding() { - @Override - public Boolean get() { - return config.getRendering().getDebug().isRenderChunkBoundingBoxes(); - } + new ReadOnlyBinding() { + @Override + public Boolean get() { + return config.getRendering().getDebug().isRenderChunkBoundingBoxes(); } + } ); } @@ -223,6 +222,4 @@ public void toggleMetricsMode() { MetricsMode mode = debugMetricsSystem.toggle(); PerformanceMonitor.setEnabled(mode.isPerformanceManagerMode()); } - - } From 6762acf73fdd97d695b648539d6c24cd60275c5e Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 5 Jan 2021 21:33:58 -0800 Subject: [PATCH 092/259] add Chunks#toChunkPos(Vector3ic, Vector3i) (#4361) --- .../java/org/terasology/world/chunks/Chunks.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/engine/src/main/java/org/terasology/world/chunks/Chunks.java b/engine/src/main/java/org/terasology/world/chunks/Chunks.java index fb7f465f1f3..1fa0453e4c5 100644 --- a/engine/src/main/java/org/terasology/world/chunks/Chunks.java +++ b/engine/src/main/java/org/terasology/world/chunks/Chunks.java @@ -116,6 +116,21 @@ public static Vector3i toChunkPos(int x, int y, int z, Vector3i dest) { return toChunkPos(x, y, z, POWER_X, POWER_Y, POWER_Z, dest); } + /** + * The position of the chunk given the coordinate and size of chunk in powers of 2. + * This uses the default power ({@link #POWER_X}, {@link #POWER_Y}, {@link #POWER_Z}) + * + *

default chunk size ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z})

+ * + * @param pos absolute coordinate of the block + * @param dest will hold the result + * @return dest + */ + public static Vector3i toChunkPos(Vector3ic pos, Vector3i dest) { + return toChunkPos(pos.x(), pos.y(), pos.z(), POWER_X, POWER_Y, POWER_Z, dest); + } + + /** * The position of the chunk given the coordinate and size of chunk in powers of 2. * From ae812412522d5e5abada7b0b51a65f5f7241bc70 Mon Sep 17 00:00:00 2001 From: Miroslav Hajda Date: Wed, 6 Jan 2021 17:58:03 +0100 Subject: [PATCH 093/259] TeraEd: Run Terasology in Swing/AWT (#4327) * TeraEd: Run Terasology in Swing/AWT * TeraEd: Run Terasology in Swing/AWT - 2 * TeraEd: Run Terasology in Swing/AWT - 3 * TeraEd: Run Terasology in Swing/AWT - 4 * TeraEd: Run Terasology in Swing/AWT - 5 * TeraEd: Run Terasology in Swing/AWT - 6 * Merge branch 'develop' into develop-teraed --- .../org/terasology/HeadlessEnvironment.java | 6 +- .../org/terasology/engine/GameEngine.java | 15 + .../org/terasology/engine/GameThread.java | 2 +- .../terasology/engine/StandardGameStatus.java | 1 + .../terasology/engine/TerasologyEngine.java | 28 +- .../engine/subsystem/DisplayDevice.java | 1 + .../engine/subsystem/DisplayDeviceInfo.java | 47 +++ .../device/HeadlessDisplayDevice.java | 7 + .../subsystem/lwjgl/GLFWErrorCallback.java | 2 +- .../subsystem/lwjgl/LwjglDisplayDevice.java | 8 + .../engine/subsystem/lwjgl/LwjglGraphics.java | 298 +----------------- .../subsystem/lwjgl/LwjglGraphicsManager.java | 230 ++++++++++++++ .../lwjgl/LwjglGraphicsProcessing.java | 8 + .../subsystem/lwjgl/LwjglGraphicsUtil.java | 117 +++++++ .../engine/subsystem/lwjgl/LwjglInput.java | 10 +- .../engine/subsystem/lwjgl/LwjglPortlet.java | 43 --- .../engine/subsystem/openvr/OpenVRInput.java | 7 +- .../event/internal/EventSystem.java | 5 + .../event/internal/EventSystemImpl.java | 5 + .../input/lwjgl/LwjglControllerDevice.java | 2 +- .../input/lwjgl/LwjglKeyboardDevice.java | 15 +- .../input/lwjgl/LwjglMouseDevice.java | 28 +- .../events/CreateVisualCharacterEvent.java | 6 +- .../internal/ReadWriteStorageManager.java | 2 +- .../recording/EventSystemReplayImpl.java | 5 + .../rendering/ShaderManagerLwjgl.java | 66 ++-- .../nui/internal/LwjglCanvasRenderer.java | 2 +- .../rendering/opengl/GLSLMaterial.java | 32 +- .../rendering/opengl/GLSLShader.java | 36 ++- .../rendering/opengl/OpenGLMesh.java | 9 +- .../rendering/opengl/OpenGLSkeletalMesh.java | 8 +- .../rendering/opengl/OpenGLTexture.java | 8 +- .../rendering/world/WorldRendererImpl.java | 4 +- .../selection/BlockSelectionRenderer.java | 1 - .../metrics/SystemContextMetric.java | 15 +- facades/TeraEd/build.gradle | 22 +- .../java/org/terasology/editor/TeraEd.java | 72 +++-- .../editor/input/AwtKeyboardDevice.java | 264 ++++++++++++++++ .../editor/input/AwtMouseDevice.java | 164 ++++++++++ .../terasology/editor/subsystem/AwtInput.java | 60 ++++ .../editor/subsystem/LwjglPortlet.java | 219 +++++++++++++ .../subsystem/LwjglPortletDisplayDevice.java | 130 ++++++++ .../org/terasology/editor/ui/Viewport.java | 21 +- 43 files changed, 1561 insertions(+), 470 deletions(-) create mode 100644 engine/src/main/java/org/terasology/engine/subsystem/DisplayDeviceInfo.java create mode 100644 engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsManager.java create mode 100644 engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsProcessing.java delete mode 100644 engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglPortlet.java create mode 100644 facades/TeraEd/src/main/java/org/terasology/editor/input/AwtKeyboardDevice.java create mode 100644 facades/TeraEd/src/main/java/org/terasology/editor/input/AwtMouseDevice.java create mode 100644 facades/TeraEd/src/main/java/org/terasology/editor/subsystem/AwtInput.java create mode 100644 facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortlet.java create mode 100644 facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortletDisplayDevice.java diff --git a/engine-tests/src/main/java/org/terasology/HeadlessEnvironment.java b/engine-tests/src/main/java/org/terasology/HeadlessEnvironment.java index 6c3ecb7aaf5..dd06b46fcbb 100644 --- a/engine-tests/src/main/java/org/terasology/HeadlessEnvironment.java +++ b/engine-tests/src/main/java/org/terasology/HeadlessEnvironment.java @@ -240,13 +240,11 @@ protected AssetManager setupAssetManager() { HeadlessMesh::new, "mesh"); assetTypeManager.registerCoreAssetType(SkeletalMesh.class, HeadlessSkeletalMesh::new, "skeletalMesh"); - assetTypeManager.registerCoreAssetType(MeshAnimation.class, - MeshAnimationImpl::new, "animations"); + assetTypeManager.registerCoreAssetType(MeshAnimation.class, MeshAnimationImpl::new, "animations"); assetTypeManager.registerCoreAssetType(Atlas.class, Atlas::new, "atlas"); - assetTypeManager.registerCoreAssetType(Subtexture.class, - Subtexture::new); + assetTypeManager.registerCoreAssetType(Subtexture.class, Subtexture::new); assetTypeManager.switchEnvironment(context.get(ModuleManager.class).getEnvironment()); diff --git a/engine/src/main/java/org/terasology/engine/GameEngine.java b/engine/src/main/java/org/terasology/engine/GameEngine.java index 2dbc2e31363..b8dee35ec31 100644 --- a/engine/src/main/java/org/terasology/engine/GameEngine.java +++ b/engine/src/main/java/org/terasology/engine/GameEngine.java @@ -46,9 +46,24 @@ public interface GameEngine { /** * Runs the engine, which will block the thread. * Invalid for a disposed engine + * + * Same as initializeRun + runMain */ void run(GameState initialState); + /** + * Performs engine initialization only and + * Invalid for a disposed engine + * + * @param initialState initial game state + */ + void initializeRun(GameState initialState); + + /** + * Runs the main loop of the engine. + */ + void runMain(); + /** * Request the engine to stop running */ diff --git a/engine/src/main/java/org/terasology/engine/GameThread.java b/engine/src/main/java/org/terasology/engine/GameThread.java index 88c35639d20..2fd240eb6a2 100644 --- a/engine/src/main/java/org/terasology/engine/GameThread.java +++ b/engine/src/main/java/org/terasology/engine/GameThread.java @@ -90,7 +90,7 @@ public static void processWaitingProcesses() { } /** - * Removes all pending processess without running them + * Removes all pending processes without running them */ public static void clearWaitingProcesses() { if (gameThread == Thread.currentThread()) { diff --git a/engine/src/main/java/org/terasology/engine/StandardGameStatus.java b/engine/src/main/java/org/terasology/engine/StandardGameStatus.java index 3a04fce4ce3..a0d4085d4ed 100644 --- a/engine/src/main/java/org/terasology/engine/StandardGameStatus.java +++ b/engine/src/main/java/org/terasology/engine/StandardGameStatus.java @@ -21,6 +21,7 @@ public enum StandardGameStatus implements EngineStatus { UNSTARTED("Unstarted"), LOADING("Loading"), RUNNING("Running"), + INITIALIZING("Initializing"), SHUTTING_DOWN("Shutting down..."), DISPOSED("Shut down"); diff --git a/engine/src/main/java/org/terasology/engine/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/TerasologyEngine.java index 88cd04dd115..a54d405a96d 100644 --- a/engine/src/main/java/org/terasology/engine/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/TerasologyEngine.java @@ -397,15 +397,41 @@ private void changeStatus(EngineStatus newStatus) { */ @Override public synchronized void run(GameState initialState) { + initializeRun(initialState); + runMain(); + } + + @Override + public synchronized void initializeRun(GameState initialState) { Preconditions.checkState(!running); running = true; + changeStatus(StandardGameStatus.INITIALIZING); initialize(); - changeStatus(StandardGameStatus.RUNNING); try { rootContext.put(GameEngine.class, this); changeState(initialState); + } catch (Throwable e) { + logger.error("Uncaught exception, attempting clean game shutdown", e); + + try { + cleanup(); + } catch (RuntimeException t) { + logger.error("Clean game shutdown after an uncaught exception failed", t); + } + running = false; + shutdownRequested = false; + changeStatus(StandardGameStatus.UNSTARTED); + throw e; + } + } + + @Override + public synchronized void runMain() { + Preconditions.checkState(running); + changeStatus(StandardGameStatus.RUNNING); + try { mainLoop(); // -THE- MAIN LOOP. Most of the application time and resources are spent here. } catch (Throwable e) { logger.error("Uncaught exception, attempting clean game shutdown", e); diff --git a/engine/src/main/java/org/terasology/engine/subsystem/DisplayDevice.java b/engine/src/main/java/org/terasology/engine/subsystem/DisplayDevice.java index 1cffaf71d2c..18bf75b4887 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/DisplayDevice.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/DisplayDevice.java @@ -78,4 +78,5 @@ public interface DisplayDevice extends Subscribable { void update(); + DisplayDeviceInfo getInfo(); } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/DisplayDeviceInfo.java b/engine/src/main/java/org/terasology/engine/subsystem/DisplayDeviceInfo.java new file mode 100644 index 00000000000..99004779f03 --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/subsystem/DisplayDeviceInfo.java @@ -0,0 +1,47 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.subsystem; + +public class DisplayDeviceInfo { + + private String openGlVendor; + private String openGlVersion; + private String openGlRenderer; + + public DisplayDeviceInfo(String openGlVendor, String openGlVersion, String openGlRenderer) { + this.openGlVendor = openGlVendor; + this.openGlVersion = openGlVersion; + this.openGlRenderer = openGlRenderer; + } + + public DisplayDeviceInfo(String unknown) { + this.openGlVendor = unknown; + this.openGlVersion = unknown; + this.openGlRenderer = unknown; + } + + public String getOpenGlVendor() { + return openGlVendor; + } + + public String getOpenGLVersion() { + return openGlVersion; + } + + public String getOpenGLRenderer() { + return openGlRenderer; + } + + public void setOpenGlVendor(String openGlVendor) { + this.openGlVendor = openGlVendor; + } + + public void setOpenGlVersion(String openGlVersion) { + this.openGlVersion = openGlVersion; + } + + public void setOpenGlRenderer(String openGlRenderer) { + this.openGlRenderer = openGlRenderer; + } +} diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/device/HeadlessDisplayDevice.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/device/HeadlessDisplayDevice.java index 150e160b336..eb3dc0f4538 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/device/HeadlessDisplayDevice.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/device/HeadlessDisplayDevice.java @@ -16,7 +16,9 @@ package org.terasology.engine.subsystem.headless.device; import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.DisplayDeviceInfo; import org.terasology.engine.subsystem.Resolution; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsUtil; import org.terasology.rendering.nui.layers.mainMenu.videoSettings.DisplayModeSetting; import org.terasology.utilities.subscribables.AbstractSubscribable; @@ -97,4 +99,9 @@ public void prepareToRender() { @Override public void update() { } + + @Override + public DisplayDeviceInfo getInfo() { + return new DisplayDeviceInfo("headless"); + } } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/GLFWErrorCallback.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/GLFWErrorCallback.java index 0f7bfac7025..d2257a0bc67 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/GLFWErrorCallback.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/GLFWErrorCallback.java @@ -12,6 +12,6 @@ public class GLFWErrorCallback implements GLFWErrorCallbackI { @Override public void invoke(int error, long description) { - logger.error("Recieved error. Code: {}, Description: {}", error, MemoryUtil.memASCII(description)); + logger.error("Received error. Code: {}, Description: {}", error, MemoryUtil.memASCII(description)); } } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglDisplayDevice.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglDisplayDevice.java index b241e5987e1..f7bf86344d7 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglDisplayDevice.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglDisplayDevice.java @@ -23,6 +23,7 @@ import org.terasology.config.RenderingConfig; import org.terasology.context.Context; import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.DisplayDeviceInfo; import org.terasology.engine.subsystem.Resolution; import org.terasology.rendering.nui.layers.mainMenu.videoSettings.DisplayModeSetting; import org.terasology.utilities.subscribables.AbstractSubscribable; @@ -47,6 +48,7 @@ public class LwjglDisplayDevice extends AbstractSubscribable implements DisplayD private final Supplier> availableResolutions = createAvailableResolutionSupplier(); private RenderingConfig config; + private DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo("unknown"); public LwjglDisplayDevice(Context context) { this.config = context.get(Config.class).getRendering(); @@ -181,6 +183,12 @@ public void prepareToRender() { glLoadIdentity(); } + @Override + public DisplayDeviceInfo getInfo() { + LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); + return displayDeviceInfo; + } + public void update() { processMessages(); GLFW.glfwSwapBuffers(GLFW.glfwGetCurrentContext()); diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphics.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphics.java index c077c81cea8..76b42f4c7f7 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphics.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphics.java @@ -15,106 +15,42 @@ */ package org.terasology.engine.subsystem.lwjgl; -import com.google.common.collect.Lists; -import com.google.common.collect.Queues; -import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWImage; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL43; import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.assets.AssetFactory; -import org.terasology.assets.module.ModuleAssetDataProducer; import org.terasology.assets.module.ModuleAwareAssetTypeManager; import org.terasology.config.Config; import org.terasology.config.RenderingConfig; import org.terasology.context.Context; import org.terasology.engine.GameEngine; -import org.terasology.engine.GameThread; import org.terasology.engine.modes.GameState; import org.terasology.engine.subsystem.DisplayDevice; -import org.terasology.engine.subsystem.RenderingSubsystemFactory; +import org.terasology.nui.canvas.CanvasRenderer; import org.terasology.rendering.ShaderManager; import org.terasology.rendering.ShaderManagerLwjgl; -import org.terasology.rendering.assets.animation.MeshAnimation; -import org.terasology.rendering.assets.animation.MeshAnimationBundle; -import org.terasology.rendering.assets.animation.MeshAnimationBundleData; -import org.terasology.rendering.assets.animation.MeshAnimationData; -import org.terasology.rendering.assets.animation.MeshAnimationImpl; -import org.terasology.rendering.assets.atlas.Atlas; -import org.terasology.rendering.assets.atlas.AtlasData; -import org.terasology.rendering.assets.font.Font; -import org.terasology.rendering.assets.font.FontData; -import org.terasology.rendering.assets.font.FontImpl; -import org.terasology.rendering.assets.material.Material; -import org.terasology.rendering.assets.material.MaterialData; -import org.terasology.rendering.assets.mesh.Mesh; -import org.terasology.rendering.assets.mesh.MeshData; -import org.terasology.rendering.assets.shader.Shader; -import org.terasology.rendering.assets.shader.ShaderData; -import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; -import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshData; -import org.terasology.rendering.assets.texture.PNGTextureFormat; -import org.terasology.rendering.assets.texture.Texture; -import org.terasology.rendering.assets.texture.TextureData; -import org.terasology.rendering.assets.texture.subtexture.Subtexture; -import org.terasology.rendering.assets.texture.subtexture.SubtextureData; -import org.terasology.nui.canvas.CanvasRenderer; import org.terasology.rendering.nui.internal.LwjglCanvasRenderer; -import org.terasology.rendering.opengl.GLSLMaterial; -import org.terasology.rendering.opengl.GLSLShader; -import org.terasology.rendering.opengl.OpenGLMesh; -import org.terasology.rendering.opengl.OpenGLSkeletalMesh; -import org.terasology.rendering.opengl.OpenGLTexture; import javax.imageio.ImageIO; -import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.concurrent.BlockingDeque; -import java.util.function.Consumer; - -import static org.lwjgl.opengl.GL11.GL_CULL_FACE; -import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; -import static org.lwjgl.opengl.GL11.GL_LEQUAL; -import static org.lwjgl.opengl.GL11.GL_NORMALIZE; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; -import static org.lwjgl.opengl.GL11.glBindTexture; -import static org.lwjgl.opengl.GL11.glDeleteTextures; -import static org.lwjgl.opengl.GL11.glDepthFunc; -import static org.lwjgl.opengl.GL11.glEnable; -import static org.lwjgl.opengl.GL11.glGenTextures; -import static org.lwjgl.opengl.GL11.glTexParameterf; public class LwjglGraphics extends BaseLwjglSubsystem { private static final Logger logger = LoggerFactory.getLogger(LwjglGraphics.class); - private GLBufferPool bufferPool = new GLBufferPool(false); - - private BlockingDeque displayThreadActions = Queues.newLinkedBlockingDeque(); - private Context context; private RenderingConfig config; private GameEngine engine; private LwjglDisplayDevice lwjglDisplay; - public static void initOpenGLParams() { - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glDepthFunc(GL_LEQUAL); - } + private LwjglGraphicsManager graphics = new LwjglGraphicsManager(); @Override public String getName() { @@ -134,64 +70,24 @@ public void initialise(GameEngine gameEngine, Context rootContext) { @Override public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { - - // cast lambdas explicitly to avoid inconsistent compiler behavior wrt. type inference - assetTypeManager.registerCoreAssetType(Font.class, - (AssetFactory) FontImpl::new, "fonts"); - assetTypeManager.registerCoreAssetType(Texture.class, (AssetFactory) - (urn, assetType, data) -> (new OpenGLTexture(urn, assetType, data, this)), "textures", "fonts"); - assetTypeManager.registerCoreFormat(Texture.class, - new PNGTextureFormat(Texture.FilterMode.NEAREST, path -> { - if (path.getName(1).toString().equals(ModuleAssetDataProducer.OVERRIDE_FOLDER)) { - return path.getName(3).toString().equals("textures"); - } else { - return path.getName(2).toString().equals("textures"); - } - })); - assetTypeManager.registerCoreFormat(Texture.class, - new PNGTextureFormat(Texture.FilterMode.LINEAR, path -> { - if (path.getName(1).toString().equals(ModuleAssetDataProducer.OVERRIDE_FOLDER)) { - return path.getName(3).toString().equals("fonts"); - } else { - return path.getName(2).toString().equals("fonts"); - } - })); - assetTypeManager.registerCoreAssetType(Shader.class, - (AssetFactory) GLSLShader::new, "shaders"); - assetTypeManager.registerCoreAssetType(Material.class, - (AssetFactory) GLSLMaterial::new, "materials"); - assetTypeManager.registerCoreAssetType(Mesh.class, (AssetFactory) - (urn, assetType, data) -> new OpenGLMesh(urn, assetType, bufferPool, data), "mesh"); - assetTypeManager.registerCoreAssetType(SkeletalMesh.class, (AssetFactory) - (urn, assetType, data) -> new OpenGLSkeletalMesh(urn, assetType, data, bufferPool), "skeletalMesh"); - assetTypeManager.registerCoreAssetType(MeshAnimation.class, - (AssetFactory) MeshAnimationImpl::new, "animations", "skeletalMesh"); - assetTypeManager.registerCoreAssetType(Atlas.class, - (AssetFactory) Atlas::new, "atlas"); - assetTypeManager.registerCoreAssetType(MeshAnimationBundle.class, - (AssetFactory) MeshAnimationBundle::new, "skeletalMesh", "animations"); - assetTypeManager.registerCoreAssetType(Subtexture.class, - (AssetFactory) Subtexture::new); + graphics.registerCoreAssetTypes(assetTypeManager); } @Override public void postInitialise(Context rootContext) { - context.put(RenderingSubsystemFactory.class, new LwjglRenderingSubsystemFactory(bufferPool)); + graphics.registerRenderingSubsystem(context); initGLFW(); initWindow(); - initOpenGL(context); + initOpenGL(); + context.put(ShaderManager.class, new ShaderManagerLwjgl()); context.put(CanvasRenderer.class, new LwjglCanvasRenderer(context)); } @Override public void postUpdate(GameState currentState, float delta) { - if (!displayThreadActions.isEmpty()) { - List actions = Lists.newArrayListWithExpectedSize(displayThreadActions.size()); - displayThreadActions.drainTo(actions); - actions.forEach(Runnable::run); - } + graphics.processActions(); currentState.render(); @@ -273,10 +169,10 @@ private void initWindow() { BufferedImage icon64 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_64.png")); BufferedImage icon128 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_128.png")); GLFWImage.Buffer buffer = GLFWImage.create(4); - buffer.put(0, convertToGLFWFormat(icon16)); - buffer.put(1, convertToGLFWFormat(icon32)); - buffer.put(2, convertToGLFWFormat(icon64)); - buffer.put(3, convertToGLFWFormat(icon128)); + buffer.put(0, LwjglGraphicsUtil.convertToGLFWFormat(icon16)); + buffer.put(1, LwjglGraphicsUtil.convertToGLFWFormat(icon32)); + buffer.put(2, LwjglGraphicsUtil.convertToGLFWFormat(icon64)); + buffer.put(3, LwjglGraphicsUtil.convertToGLFWFormat(icon128)); GLFW.glfwSetWindowIcon(window, buffer); } catch (IOException | IllegalArgumentException e) { @@ -288,49 +184,16 @@ private void initWindow() { GLFW.glfwShowWindow(window); } - /** - * Converting BufferedImage to GLFWImage - * - * @param image image to convert - * @return convertedImage - */ - private GLFWImage convertToGLFWFormat(BufferedImage image) { - BufferedImage convertedImage; - if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { - convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), - BufferedImage.TYPE_INT_ARGB_PRE); - final Graphics2D graphics = convertedImage.createGraphics(); - final int targetWidth = image.getWidth(); - final int targetHeight = image.getHeight(); - graphics.drawImage(image, 0, 0, targetWidth, targetHeight, null); - graphics.dispose(); - } - final ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); - for (int i = 0; i < image.getHeight(); i++) { - for (int j = 0; j < image.getWidth(); j++) { - int colorSpace = image.getRGB(j, i); - buffer.put((byte) ((colorSpace << 8) >> 24)); - buffer.put((byte) ((colorSpace << 16) >> 24)); - buffer.put((byte) ((colorSpace << 24) >> 24)); - buffer.put((byte) (colorSpace >> 24)); - } - } - buffer.flip(); - final GLFWImage result = GLFWImage.create(); - result.set(image.getWidth(), image.getHeight(), buffer); - return result; - } - - private void initOpenGL(Context currentContext) { + private void initOpenGL() { logger.info("Initializing OpenGL"); - checkOpenGL(); + LwjglGraphicsUtil.checkOpenGL(); GLFW.glfwSetFramebufferSizeCallback(GLFW.glfwGetCurrentContext(), new GLFWFramebufferSizeCallback() { @Override public void invoke(long window, int width, int height) { lwjglDisplay.updateViewport(width, height); } }); - initOpenGLParams(); + LwjglGraphicsUtil.initOpenGLParams(); if (config.getDebug().isEnabled()) { try { GL43.glDebugMessageCallback(new DebugCallback(), MemoryUtil.NULL); @@ -338,138 +201,5 @@ public void invoke(long window, int width, int height) { logger.warn("Unable to specify DebugCallback to receive debugging messages from the GL."); } } - currentContext.put(ShaderManager.class, new ShaderManagerLwjgl()); - } - - private void checkOpenGL() { - GLCapabilities capabilities = GL.createCapabilities(); - boolean[] requiredCapabilities = { - capabilities.OpenGL12, - capabilities.OpenGL14, - capabilities.OpenGL15, - capabilities.OpenGL20, - capabilities.OpenGL21, // needed as we use GLSL 1.20 - - capabilities.GL_ARB_framebuffer_object, // Extensions eventually included in - capabilities.GL_ARB_texture_float, // OpenGl 3.0 according to - capabilities.GL_ARB_half_float_pixel}; // http://en.wikipedia.org/wiki/OpenGL#OpenGL_3.0 - - String[] capabilityNames = {"OpenGL12", - "OpenGL14", - "OpenGL15", - "OpenGL20", - "OpenGL21", - "GL_ARB_framebuffer_object", - "GL_ARB_texture_float", - "GL_ARB_half_float_pixel"}; - - boolean canRunTheGame = true; - StringBuilder missingCapabilitiesMessage = new StringBuilder(); - - for (int index = 0; index < requiredCapabilities.length; index++) { - if (!requiredCapabilities[index]) { - missingCapabilitiesMessage.append(" - ").append(capabilityNames[index]).append("\n"); - canRunTheGame = false; - } - } - - if (!canRunTheGame) { - String completeErrorMessage = completeErrorMessage(missingCapabilitiesMessage.toString()); - throw new IllegalStateException(completeErrorMessage); - } - } - - private String completeErrorMessage(String errorMessage) { - return "\n" + - "\nThe following OpenGL versions/extensions are required but are not supported by your GPU driver:\n" + - "\n" + - errorMessage + - "\n" + - "GPU Information:\n" + - "\n" + - " Vendor: " + GL11.glGetString(GL11.GL_VENDOR) + "\n" + - " Model: " + GL11.glGetString(GL11.GL_RENDERER) + "\n" + - " Driver: " + GL11.glGetString(GL11.GL_VERSION) + "\n" + - "\n" + - "Try updating the driver to the latest version available.\n" + - "If that fails you might need to use a different GPU (graphics card). Sorry!\n"; - } - - public void asynchToDisplayThread(Runnable action) { - if (GameThread.isCurrentThread()) { - action.run(); - } else { - displayThreadActions.add(action); - } - } - - public void createTexture3D(ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, - int size, Consumer idConsumer) { - asynchToDisplayThread(() -> { - int id = glGenTextures(); - reloadTexture3D(id, alignedBuffer, wrapMode, filterMode, size); - idConsumer.accept(id); - }); - } - - public void reloadTexture3D(int id, ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, - Texture.FilterMode filterMode, int size) { - asynchToDisplayThread(() -> { - glBindTexture(GL12.GL_TEXTURE_3D, id); - - glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, LwjglGraphicsUtil.getGLMode(wrapMode)); - - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, - LwjglGraphicsUtil.getGlMinFilter(filterMode)); - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, - LwjglGraphicsUtil.getGlMagFilter(filterMode)); - - GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); - GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_MAX_LEVEL, 0); - - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL11.GL_RGBA, size, size, size, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, alignedBuffer); - }); - } - - public void createTexture2D(ByteBuffer[] buffers, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, - int width, int height, Consumer idConsumer) { - asynchToDisplayThread(() -> { - int id = glGenTextures(); - reloadTexture2D(id, buffers, wrapMode, filterMode, width, height); - idConsumer.accept(id); - }); - } - - public void reloadTexture2D(int id, ByteBuffer[] buffers, Texture.WrapMode wrapMode, - Texture.FilterMode filterMode, int width, int height) { - asynchToDisplayThread(() -> { - glBindTexture(GL11.GL_TEXTURE_2D, id); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); - GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, - LwjglGraphicsUtil.getGlMinFilter(filterMode)); - GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, - LwjglGraphicsUtil.getGlMagFilter(filterMode)); - GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, buffers.length - 1); - - if (buffers.length > 0) { - for (int i = 0; i < buffers.length; i++) { - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, i, GL11.GL_RGBA, width >> i, height >> i, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, buffers[i]); - } - } else { - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); - } - }); - } - - public void disposeTexture(int id) { - asynchToDisplayThread(() -> glDeleteTextures(id)); } } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsManager.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsManager.java new file mode 100644 index 00000000000..6708de0c322 --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsManager.java @@ -0,0 +1,230 @@ +/* + * Copyright 2017 MovingBlocks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.terasology.engine.subsystem.lwjgl; + +import com.google.common.collect.Lists; +import com.google.common.collect.Queues; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.terasology.assets.AssetFactory; +import org.terasology.assets.module.ModuleAssetDataProducer; +import org.terasology.assets.module.ModuleAwareAssetTypeManager; +import org.terasology.context.Context; +import org.terasology.engine.GameThread; +import org.terasology.engine.subsystem.DisplayDeviceInfo; +import org.terasology.engine.subsystem.RenderingSubsystemFactory; +import org.terasology.rendering.assets.animation.MeshAnimation; +import org.terasology.rendering.assets.animation.MeshAnimationBundle; +import org.terasology.rendering.assets.animation.MeshAnimationBundleData; +import org.terasology.rendering.assets.animation.MeshAnimationImpl; +import org.terasology.rendering.assets.atlas.Atlas; +import org.terasology.rendering.assets.font.Font; +import org.terasology.rendering.assets.font.FontData; +import org.terasology.rendering.assets.font.FontImpl; +import org.terasology.rendering.assets.material.Material; +import org.terasology.rendering.assets.material.MaterialData; +import org.terasology.rendering.assets.mesh.Mesh; +import org.terasology.rendering.assets.mesh.MeshData; +import org.terasology.rendering.assets.shader.Shader; +import org.terasology.rendering.assets.shader.ShaderData; +import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; +import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshData; +import org.terasology.rendering.assets.texture.PNGTextureFormat; +import org.terasology.rendering.assets.texture.Texture; +import org.terasology.rendering.assets.texture.TextureData; +import org.terasology.rendering.assets.texture.subtexture.Subtexture; +import org.terasology.rendering.assets.texture.subtexture.SubtextureData; +import org.terasology.rendering.opengl.GLSLMaterial; +import org.terasology.rendering.opengl.GLSLShader; +import org.terasology.rendering.opengl.OpenGLMesh; +import org.terasology.rendering.opengl.OpenGLSkeletalMesh; +import org.terasology.rendering.opengl.OpenGLTexture; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.BlockingDeque; +import java.util.function.Consumer; + +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL11.glDeleteTextures; +import static org.lwjgl.opengl.GL11.glGenTextures; +import static org.lwjgl.opengl.GL11.glTexParameterf; + +public class LwjglGraphicsManager implements LwjglGraphicsProcessing { + + private final GLBufferPool bufferPool = new GLBufferPool(false); + + private final BlockingDeque displayThreadActions = Queues.newLinkedBlockingDeque(); + + private DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo("unknown"); + private ThreadMode threadMode = ThreadMode.GAME_THREAD; + + public void setThreadMode(ThreadMode threadMode) { + this.threadMode = threadMode; + } + + public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { + // cast lambdas explicitly to avoid inconsistent compiler behavior wrt. type inference + assetTypeManager.registerCoreAssetType(Font.class, + (AssetFactory) FontImpl::new, "fonts"); + assetTypeManager.registerCoreAssetType(Texture.class, (AssetFactory) + (urn, assetType, data) -> (new OpenGLTexture(urn, assetType, data, this)), "textures", "fonts"); + assetTypeManager.registerCoreFormat(Texture.class, + new PNGTextureFormat(Texture.FilterMode.NEAREST, path -> { + if (path.getName(1).toString().equals(ModuleAssetDataProducer.OVERRIDE_FOLDER)) { + return path.getName(3).toString().equals("textures"); + } else { + return path.getName(2).toString().equals("textures"); + } + })); + assetTypeManager.registerCoreFormat(Texture.class, + new PNGTextureFormat(Texture.FilterMode.LINEAR, path -> { + if (path.getName(1).toString().equals(ModuleAssetDataProducer.OVERRIDE_FOLDER)) { + return path.getName(3).toString().equals("fonts"); + } else { + return path.getName(2).toString().equals("fonts"); + } + })); + assetTypeManager.registerCoreAssetType(Shader.class, + (AssetFactory) (urn, assetType, data) -> + new GLSLShader(urn, assetType, data, this), + "shaders"); + assetTypeManager.registerCoreAssetType(Material.class, + (AssetFactory) (urn, assetType, data) -> + new GLSLMaterial(urn, assetType, data, this), + "materials"); + assetTypeManager.registerCoreAssetType(Mesh.class, (AssetFactory) + (urn, assetType, data) -> + new OpenGLMesh(urn, assetType, bufferPool, data, this), + "mesh"); + assetTypeManager.registerCoreAssetType(SkeletalMesh.class, (AssetFactory) + (urn, assetType, data) -> + new OpenGLSkeletalMesh(urn, assetType, bufferPool, data, this), + "skeletalMesh"); + assetTypeManager.registerCoreAssetType(MeshAnimation.class, MeshAnimationImpl::new, + "animations", "skeletalMesh"); + assetTypeManager.registerCoreAssetType(Atlas.class, Atlas::new, "atlas"); + assetTypeManager.registerCoreAssetType(MeshAnimationBundle.class, + (AssetFactory) MeshAnimationBundle::new, + "skeletalMesh", "animations"); + assetTypeManager.registerCoreAssetType(Subtexture.class, + (AssetFactory) Subtexture::new); + } + + public void registerRenderingSubsystem(Context context) { + context.put(RenderingSubsystemFactory.class, new LwjglRenderingSubsystemFactory(bufferPool)); + } + + public void processActions() { + LwjglGraphicsUtil.updateDisplayDeviceInfo(displayDeviceInfo); + + if (!displayThreadActions.isEmpty()) { + List actions = Lists.newArrayListWithExpectedSize(displayThreadActions.size()); + displayThreadActions.drainTo(actions); + actions.forEach(Runnable::run); + } + } + + public void asynchToDisplayThread(Runnable action) { + if (threadMode == ThreadMode.GAME_THREAD && GameThread.isCurrentThread()) { + action.run(); + } else { + displayThreadActions.add(action); + } + } + + public void createTexture3D(ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, + int size, Consumer idConsumer) { + asynchToDisplayThread(() -> { + int id = glGenTextures(); + reloadTexture3D(id, alignedBuffer, wrapMode, filterMode, size); + idConsumer.accept(id); + }); + } + + public void reloadTexture3D(int id, ByteBuffer alignedBuffer, Texture.WrapMode wrapMode, + Texture.FilterMode filterMode, int size) { + asynchToDisplayThread(() -> { + glBindTexture(GL12.GL_TEXTURE_3D, id); + + glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); + glTexParameterf(GL12.GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); + glTexParameterf(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, LwjglGraphicsUtil.getGLMode(wrapMode)); + + GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, + LwjglGraphicsUtil.getGlMinFilter(filterMode)); + GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, + LwjglGraphicsUtil.getGlMagFilter(filterMode)); + + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); + GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_MAX_LEVEL, 0); + + GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL11.GL_RGBA, size, size, size, 0, GL11.GL_RGBA, + GL11.GL_UNSIGNED_BYTE, alignedBuffer); + }); + } + + public void createTexture2D(ByteBuffer[] buffers, Texture.WrapMode wrapMode, Texture.FilterMode filterMode, + int width, int height, Consumer idConsumer) { + asynchToDisplayThread(() -> { + int id = glGenTextures(); + reloadTexture2D(id, buffers, wrapMode, filterMode, width, height); + idConsumer.accept(id); + }); + } + + public void reloadTexture2D(int id, ByteBuffer[] buffers, Texture.WrapMode wrapMode, + Texture.FilterMode filterMode, int width, int height) { + asynchToDisplayThread(() -> { + glBindTexture(GL11.GL_TEXTURE_2D, id); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, LwjglGraphicsUtil.getGLMode(wrapMode)); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, LwjglGraphicsUtil.getGLMode(wrapMode)); + GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, + LwjglGraphicsUtil.getGlMinFilter(filterMode)); + GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, + LwjglGraphicsUtil.getGlMagFilter(filterMode)); + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, buffers.length - 1); + + if (buffers.length > 0) { + for (int i = 0; i < buffers.length; i++) { + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, i, GL11.GL_RGBA, width >> i, height >> i, 0, GL11.GL_RGBA, + GL11.GL_UNSIGNED_BYTE, buffers[i]); + } + } else { + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, + GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); + } + }); + } + + public void disposeTexture(int id) { + asynchToDisplayThread(() -> glDeleteTextures(id)); + } + + public DisplayDeviceInfo getDisplayDeviceInfo() { + return displayDeviceInfo; + } + + public enum ThreadMode { + GAME_THREAD, + DISPLAY_THREAD + } +} diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsProcessing.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsProcessing.java new file mode 100644 index 00000000000..63fb2b83f0d --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsProcessing.java @@ -0,0 +1,8 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.subsystem.lwjgl; + +public interface LwjglGraphicsProcessing { + void asynchToDisplayThread(Runnable action); +} diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsUtil.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsUtil.java index 0b62200acf6..1ed894f885e 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsUtil.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglGraphicsUtil.java @@ -15,16 +15,33 @@ */ package org.terasology.engine.subsystem.lwjgl; +import org.lwjgl.BufferUtils; +import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GLCapabilities; +import org.terasology.engine.subsystem.DisplayDeviceInfo; import org.terasology.rendering.assets.texture.Texture; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; + import static org.lwjgl.opengl.GL11.GL_CLAMP; +import static org.lwjgl.opengl.GL11.GL_CULL_FACE; +import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; +import static org.lwjgl.opengl.GL11.GL_LEQUAL; import static org.lwjgl.opengl.GL11.GL_LINEAR; import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_LINEAR; import static org.lwjgl.opengl.GL11.GL_NEAREST; import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_NEAREST; +import static org.lwjgl.opengl.GL11.GL_NORMALIZE; import static org.lwjgl.opengl.GL11.GL_REPEAT; +import static org.lwjgl.opengl.GL11.glDepthFunc; +import static org.lwjgl.opengl.GL11.glEnable; /** + * */ public final class LwjglGraphicsUtil { private LwjglGraphicsUtil() { @@ -62,4 +79,104 @@ public static int getGlMagFilter(Texture.FilterMode filterMode2) { throw new RuntimeException("Unsupported FilterMode '" + filterMode2 + "'"); } } + + /** + * Converting BufferedImage to GLFWImage. + * + * @param image image to convert + * @return convertedImage + */ + public static GLFWImage convertToGLFWFormat(BufferedImage image) { + BufferedImage convertedImage; + if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { + convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), + BufferedImage.TYPE_INT_ARGB_PRE); + final Graphics2D graphics = convertedImage.createGraphics(); + final int targetWidth = image.getWidth(); + final int targetHeight = image.getHeight(); + graphics.drawImage(image, 0, 0, targetWidth, targetHeight, null); + graphics.dispose(); + } + final ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); + for (int i = 0; i < image.getHeight(); i++) { + for (int j = 0; j < image.getWidth(); j++) { + int colorSpace = image.getRGB(j, i); + buffer.put((byte) ((colorSpace << 8) >> 24)); + buffer.put((byte) ((colorSpace << 16) >> 24)); + buffer.put((byte) ((colorSpace << 24) >> 24)); + buffer.put((byte) (colorSpace >> 24)); + } + } + buffer.flip(); + final GLFWImage result = GLFWImage.create(); + result.set(image.getWidth(), image.getHeight(), buffer); + return result; + } + + public static void initOpenGLParams() { + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glDepthFunc(GL_LEQUAL); + } + + public static void checkOpenGL() { + GLCapabilities capabilities = GL.createCapabilities(); + boolean[] requiredCapabilities = { + capabilities.OpenGL12, + capabilities.OpenGL14, + capabilities.OpenGL15, + capabilities.OpenGL20, + capabilities.OpenGL21, // needed as we use GLSL 1.20 + + capabilities.GL_ARB_framebuffer_object, // Extensions eventually included in + capabilities.GL_ARB_texture_float, // OpenGl 3.0 according to + capabilities.GL_ARB_half_float_pixel}; // http://en.wikipedia.org/wiki/OpenGL#OpenGL_3.0 + + String[] capabilityNames = {"OpenGL12", + "OpenGL14", + "OpenGL15", + "OpenGL20", + "OpenGL21", + "GL_ARB_framebuffer_object", + "GL_ARB_texture_float", + "GL_ARB_half_float_pixel"}; + + boolean canRunTheGame = true; + StringBuilder missingCapabilitiesMessage = new StringBuilder(); + + for (int index = 0; index < requiredCapabilities.length; index++) { + if (!requiredCapabilities[index]) { + missingCapabilitiesMessage.append(" - ").append(capabilityNames[index]).append("\n"); + canRunTheGame = false; + } + } + + if (!canRunTheGame) { + String completeErrorMessage = completeErrorMessage(missingCapabilitiesMessage.toString()); + throw new IllegalStateException(completeErrorMessage); + } + } + + private static String completeErrorMessage(String errorMessage) { + return "\n" + + "\nThe following OpenGL versions/extensions are required but are not supported by your GPU driver:\n" + + "\n" + + errorMessage + + "\n" + + "GPU Information:\n" + + "\n" + + " Vendor: " + GL11.glGetString(GL11.GL_VENDOR) + "\n" + + " Model: " + GL11.glGetString(GL11.GL_RENDERER) + "\n" + + " Driver: " + GL11.glGetString(GL11.GL_VERSION) + "\n" + + "\n" + + "Try updating the driver to the latest version available.\n" + + "If that fails you might need to use a different GPU (graphics card). Sorry!\n"; + } + + public static void updateDisplayDeviceInfo(DisplayDeviceInfo deviceInfo) { + deviceInfo.setOpenGlVendor(GL11.glGetString(GL11.GL_VENDOR)); + deviceInfo.setOpenGlVersion(GL11.glGetString(GL11.GL_VERSION)); + deviceInfo.setOpenGlRenderer(GL11.glGetString(GL11.GL_RENDERER)); + } } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglInput.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglInput.java index b6015d23fd9..9f6cd37011c 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglInput.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglInput.java @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.subsystem.lwjgl; +import org.lwjgl.glfw.GLFW; import org.terasology.assets.module.ModuleAwareAssetTypeManager; import org.terasology.config.Config; import org.terasology.config.ControllerConfig; +import org.terasology.config.RenderingConfig; import org.terasology.context.Context; import org.terasology.engine.modes.GameState; import org.terasology.engine.subsystem.config.BindsManager; @@ -39,16 +41,20 @@ public void postUpdate(GameState currentState, float delta) { } private void initControls() { + Config config = context.get(Config.class); InputSystem inputSystem = new InputSystem(); context.put(InputSystem.class, inputSystem); - inputSystem.setMouseDevice(new LwjglMouseDevice(context)); + inputSystem.setMouseDevice(new LwjglMouseDevice(config.getRendering())); inputSystem.setKeyboardDevice(new LwjglKeyboardDevice()); - ControllerConfig controllerConfig = context.get(Config.class).getInput().getControllers(); + ControllerConfig controllerConfig = config.getInput().getControllers(); LwjglControllerDevice controllerDevice = new LwjglControllerDevice(controllerConfig); inputSystem.setControllerDevice(controllerDevice); + long window = GLFW.glfwGetCurrentContext(); + ((LwjglKeyboardDevice) inputSystem.getKeyboard()).registerToLwjglWindow(window); + ((LwjglMouseDevice) inputSystem.getMouseDevice()).registerToLwjglWindow(window); } private void updateInputConfig() { diff --git a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglPortlet.java b/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglPortlet.java deleted file mode 100644 index 80457c2848e..00000000000 --- a/engine/src/main/java/org/terasology/engine/subsystem/lwjgl/LwjglPortlet.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.engine.subsystem.lwjgl; - -import java.awt.Canvas; - -import org.terasology.context.Context; - -public class LwjglPortlet extends BaseLwjglSubsystem { - - private Canvas customViewPort; - - @Override - public String getName() { - return "Portlet"; - } - - @Override - public void postInitialise(Context context) { - // FIXME: LWJGL 3 haven't classes for working with awt. - // Used by TeraED facade only. - // Needs rework TeraED rendering part. - throw new RuntimeException("Not implemented"); - } - - public void setCustomViewport(Canvas canvas) { - this.customViewPort = canvas; - } - -} diff --git a/engine/src/main/java/org/terasology/engine/subsystem/openvr/OpenVRInput.java b/engine/src/main/java/org/terasology/engine/subsystem/openvr/OpenVRInput.java index 28b27154a20..74417919bec 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/openvr/OpenVRInput.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/openvr/OpenVRInput.java @@ -14,6 +14,7 @@ * limitations under the License. */ package org.terasology.engine.subsystem.openvr; +import org.lwjgl.glfw.GLFW; import org.terasology.assets.module.ModuleAwareAssetTypeManager; import org.terasology.config.Config; import org.terasology.context.Context; @@ -76,9 +77,13 @@ public void postInitialise(Context rootContext) { InputSystem inputSystem = context.get(InputSystem.class); if (inputSystem == null) { inputSystem = new InputSystem(); - inputSystem.setMouseDevice(new LwjglMouseDevice(context)); + inputSystem.setMouseDevice(new LwjglMouseDevice(config.getRendering())); inputSystem.setKeyboardDevice(new LwjglKeyboardDevice()); context.put(InputSystem.class, inputSystem); + + long window = GLFW.glfwGetCurrentContext(); + ((LwjglKeyboardDevice) inputSystem.getKeyboard()).registerToLwjglWindow(window); + ((LwjglMouseDevice) inputSystem.getMouseDevice()).registerToLwjglWindow(window); } controllerDevice = new OpenVRControllers(); diff --git a/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystem.java b/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystem.java index aeeb10039e6..a9b6a562f0d 100644 --- a/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystem.java +++ b/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystem.java @@ -90,4 +90,9 @@ public interface EventSystem { * @param component */ void send(EntityRef entity, Event event, Component component); + + /** + * Change main thread to current thread. + */ + void setToCurrentThread(); } diff --git a/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystemImpl.java b/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystemImpl.java index 59f012efe84..7bf4670255a 100644 --- a/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystemImpl.java +++ b/engine/src/main/java/org/terasology/entitySystem/event/internal/EventSystemImpl.java @@ -406,6 +406,11 @@ private Set selectEventHandlers(Class eventTy return result; } + @Override + public void setToCurrentThread() { + mainThread = Thread.currentThread(); + } + private static class EventHandlerPriorityComparator implements Comparator { @Override diff --git a/engine/src/main/java/org/terasology/input/lwjgl/LwjglControllerDevice.java b/engine/src/main/java/org/terasology/input/lwjgl/LwjglControllerDevice.java index 0664512480f..b5b13737de3 100644 --- a/engine/src/main/java/org/terasology/input/lwjgl/LwjglControllerDevice.java +++ b/engine/src/main/java/org/terasology/input/lwjgl/LwjglControllerDevice.java @@ -175,7 +175,7 @@ public Queue getInputQueue() { controllerActions.add(new ControllerAction(input, controllerName, ButtonState.UP, axisValue)); } - logger.error("Recieved unknown/unhandled buttonId for GLFW: {}", buttonIndex); + logger.error("Received unknown/unhandled buttonId for GLFW: {}", buttonIndex); } else { Input input = InputType.CONTROLLER_BUTTON.getInput(teraButtonId); diff --git a/engine/src/main/java/org/terasology/input/lwjgl/LwjglKeyboardDevice.java b/engine/src/main/java/org/terasology/input/lwjgl/LwjglKeyboardDevice.java index ec776541ec5..2928b18cdf2 100644 --- a/engine/src/main/java/org/terasology/input/lwjgl/LwjglKeyboardDevice.java +++ b/engine/src/main/java/org/terasology/input/lwjgl/LwjglKeyboardDevice.java @@ -11,6 +11,10 @@ import org.lwjgl.glfw.GLFW; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.terasology.context.Context; +import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.lwjgl.LwjglDisplayDevice; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphics; import org.terasology.input.ButtonState; import org.terasology.input.Input; import org.terasology.input.InputType; @@ -22,7 +26,7 @@ import java.util.Queue; /** - * Lwjgl 3's (GLFW) keyboard device represenation. + * Lwjgl 3's (GLFW) keyboard device representation. * Handles keyboard input via GLFW's callbacks. */ public class LwjglKeyboardDevice implements KeyboardDevice { @@ -170,25 +174,26 @@ public class LwjglKeyboardDevice implements KeyboardDevice { private TIntSet buttonStates = new TIntHashSet(); public LwjglKeyboardDevice() { - long window = GLFW.glfwGetCurrentContext(); + } + public void registerToLwjglWindow(long window) { GLFW.glfwSetKeyCallback(window, this::glfwKeyCallback); GLFW.glfwSetCharCallback(window, this::glfwCharCallback); } /** - * Callback recieve char input events from windowing systems. Used for text typing. You cannot recieve key, + * Callback receive char input events from windowing systems. Used for text typing. You cannot receive key, * non-printables(mods keys, etc). * * @param window window's pointer - * @param chr recieved char, affected by keyboard layout and modifications. + * @param chr received char, affected by keyboard layout and modifications. */ private void glfwCharCallback(long window, int chr) { charQueue.offer(new CharKeyboardAction((char) chr)); } /** - * Callback recieve key input events. All keys in{@link GLFW} + * Callback receive key input events. All keys in {@link GLFW} * * @param window window's pointer * @param key one of key listed in {@link GLFW} GLFW_KEY*, also you can see {@link diff --git a/engine/src/main/java/org/terasology/input/lwjgl/LwjglMouseDevice.java b/engine/src/main/java/org/terasology/input/lwjgl/LwjglMouseDevice.java index 947edc49a22..096f6d52d05 100644 --- a/engine/src/main/java/org/terasology/input/lwjgl/LwjglMouseDevice.java +++ b/engine/src/main/java/org/terasology/input/lwjgl/LwjglMouseDevice.java @@ -10,9 +10,7 @@ import org.joml.Vector2i; import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFW; -import org.terasology.config.Config; import org.terasology.config.RenderingConfig; -import org.terasology.context.Context; import org.terasology.input.ButtonState; import org.terasology.input.InputType; import org.terasology.input.MouseInput; @@ -25,8 +23,8 @@ import java.util.Queue; /** - * Lwjgl 3's (GLFW) mouse device represenation. - * Handles mouse input via GLFW's callbacks + * Lwjgl 3's (GLFW) mouse device representation. + * Handles mouse input via GLFW's callbacks. * Handles mouse state. */ public class LwjglMouseDevice implements MouseDevice, PropertyChangeListener { @@ -43,21 +41,19 @@ public class LwjglMouseDevice implements MouseDevice, PropertyChangeListener { private double xposDelta; private double yposDelta; - public LwjglMouseDevice(Context context) { - this.renderingConfig = context.get(Config.class).getRendering(); - this.uiScale = this.renderingConfig.getUiScale() / 100f; - this.renderingConfig.subscribe(RenderingConfig.UI_SCALE, this); + public LwjglMouseDevice(RenderingConfig renderingConfig) { + this.renderingConfig = renderingConfig; + this.uiScale = renderingConfig.getUiScale() / 100f; + renderingConfig.subscribe(RenderingConfig.UI_SCALE, this); + } - // GLFW callback - long window = GLFW.glfwGetCurrentContext(); + public void registerToLwjglWindow(long window) { GLFW.glfwSetMouseButtonCallback(window, this::mouseButtonCallback); GLFW.glfwSetScrollCallback(window, this::scrollCallback); - } - @Override - public void update() { + public void update() { long window = GLFW.glfwGetCurrentContext(); DoubleBuffer mouseX = BufferUtils.createDoubleBuffer(1); DoubleBuffer mouseY = BufferUtils.createDoubleBuffer(1); @@ -66,6 +62,10 @@ public void update() { mouseX.rewind(); mouseY.rewind(); + GLFW.glfwGetCursorPos(window, mouseX, mouseY); + mouseX.rewind(); + mouseY.rewind(); + double x = mouseX.get(0); double y = mouseY.get(0); @@ -77,7 +77,7 @@ public void update() { @Override public Vector2i getPosition() { - return new Vector2i((int) (xpos / this.uiScale), (int) (ypos / this.uiScale)); + return new Vector2i((int) (xpos / this.uiScale), (int) (ypos / this.uiScale)); } @Override diff --git a/engine/src/main/java/org/terasology/logic/characters/events/CreateVisualCharacterEvent.java b/engine/src/main/java/org/terasology/logic/characters/events/CreateVisualCharacterEvent.java index 54b6bd08520..671684d6516 100644 --- a/engine/src/main/java/org/terasology/logic/characters/events/CreateVisualCharacterEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/events/CreateVisualCharacterEvent.java @@ -21,13 +21,13 @@ import org.terasology.logic.characters.VisualCharacterComponent; /** - * Sent to the character entities when a visual represenation of it should be created for them: The event will be send + * Sent to the character entities when a visual representation of it should be created for them: The event will be send * to characters that have the {@link VisualCharacterComponent}. * * When you want to create a new type of visual character just create a handler for this event and consume it. - * The handler should create the visual represenation of the character via the builder provided by the even.t + * The handler should create the visual representation of the character via the builder provided by the even.t * - * There is a default handling on {@link EventPriority#PRIORITY_TRIVIAL}. The defualt handler creates + * There is a default handling on {@link EventPriority#PRIORITY_TRIVIAL}. The default handler creates * a placeholder character. To prevent this placeholder character to be created the event must be consumed * by a handler that creates its own visual character. * diff --git a/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java b/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java index 7885c3b763f..4fc61269209 100644 --- a/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java +++ b/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java @@ -218,7 +218,7 @@ private void addChunksToSaveTransaction(SaveTransactionBuilder saveTransactionBu unloadedAndSavingChunkMap.clear(); /* * New entries might be added concurrently. By using putAll + clear to transfer entries we might loose new - * ones added in between putAll and clear. Bz iterating we can make sure that all entires removed + * ones added in between putAll and clear. By iterating we can make sure that all entries removed * from unloadedAndUnsavedChunkMap get added to unloadedAndSavingChunkMap. */ Iterator> unsavedEntryIterator = unloadedAndUnsavedChunkMap.entrySet().iterator(); diff --git a/engine/src/main/java/org/terasology/recording/EventSystemReplayImpl.java b/engine/src/main/java/org/terasology/recording/EventSystemReplayImpl.java index bc037e52a89..090524496f3 100644 --- a/engine/src/main/java/org/terasology/recording/EventSystemReplayImpl.java +++ b/engine/src/main/java/org/terasology/recording/EventSystemReplayImpl.java @@ -370,6 +370,11 @@ public void unregisterEventHandler(ComponentSystem handler) { } } + @Override + public void setToCurrentThread() { + mainThread = Thread.currentThread(); + } + private void addEventHandler(Class type, EventSystemReplayImpl.EventHandlerInfo handler, Collection> components) { if (components.isEmpty()) { generalHandlers.put(type, handler); diff --git a/engine/src/main/java/org/terasology/rendering/ShaderManagerLwjgl.java b/engine/src/main/java/org/terasology/rendering/ShaderManagerLwjgl.java index e990f992607..346051e76ae 100644 --- a/engine/src/main/java/org/terasology/rendering/ShaderManagerLwjgl.java +++ b/engine/src/main/java/org/terasology/rendering/ShaderManagerLwjgl.java @@ -52,41 +52,11 @@ public class ShaderManagerLwjgl implements ShaderManager { private Set progamaticShaders = Sets.newHashSet(); public ShaderManagerLwjgl() { - logger.info("Loading Terasology shader manager..."); - logger.info("LWJGL: {} / {}", Version.getVersion(), Platform.get().getName()); - logger.info("GL_VENDOR: {}", GL11.glGetString(GL11.GL_VENDOR)); - logger.info("GL_RENDERER: {}", GL11.glGetString(GL11.GL_RENDERER)); - logger.info("GL_VERSION: {}", GL11.glGetString(GL11.GL_VERSION)); - logger.info("SHADING_LANGUAGE VERSION: {}", GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION)); - - String extStr = GL11.glGetString(GL11.GL_EXTENSIONS); - - // log shader extensions in smaller packages, - // because the full string can be extremely long - int extsPerLine = 8; - - // starting with OpenGL 3.0, extensions can also listed using - // GL_NUM_EXTENSIONS and glGetStringi(GL_EXTENSIONS, idx) - String[] exts = extStr.split(" "); - if (exts.length > 0) { - StringBuilder bldr = new StringBuilder(exts[0]); - for (int i = 1; i < exts.length; i++) { - if (i % extsPerLine == 0) { - logger.info("EXTENSIONS: {}", bldr.toString()); - bldr.setLength(0); - } else { - bldr.append(" "); - } - bldr.append(exts[i]); - } - if (bldr.length() > 0) { - logger.info("EXTENSIONS: {}", bldr.toString()); - } - } } @Override public void initShaders() { + logCapabilities(); defaultShaderProgram = addShaderProgram("default"); defaultTexturedShaderProgram = addShaderProgram("defaultTextured"); @@ -114,6 +84,40 @@ public void initShaders() { addShaderProgram("ssaoBlur"); } + private void logCapabilities() { + logger.info("Loading Terasology shader manager..."); + logger.info("LWJGL: {} / {}", Version.getVersion(), Platform.get().getName()); + logger.info("GL_VENDOR: {}", GL11.glGetString(GL11.GL_VENDOR)); + logger.info("GL_RENDERER: {}", GL11.glGetString(GL11.GL_RENDERER)); + logger.info("GL_VERSION: {}", GL11.glGetString(GL11.GL_VERSION)); + logger.info("SHADING_LANGUAGE VERSION: {}", GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION)); + + String extStr = GL11.glGetString(GL11.GL_EXTENSIONS); + + // log shader extensions in smaller packages, + // because the full string can be extremely long + int extsPerLine = 8; + + // starting with OpenGL 3.0, extensions can also listed using + // GL_NUM_EXTENSIONS and glGetStringi(GL_EXTENSIONS, idx) + String[] exts = extStr.split(" "); + if (exts.length > 0) { + StringBuilder bldr = new StringBuilder(exts[0]); + for (int i = 1; i < exts.length; i++) { + if (i % extsPerLine == 0) { + logger.info("EXTENSIONS: {}", bldr.toString()); + bldr.setLength(0); + } else { + bldr.append(" "); + } + bldr.append(exts[i]); + } + if (bldr.length() > 0) { + logger.info("EXTENSIONS: {}", bldr.toString()); + } + } + } + @Override public void setActiveMaterial(Material material) { // TODO: is this the best way to convert the material to the lwjgl version? Do we need more checks? diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java index 83e7aa274b8..19d91e0889e 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java @@ -88,7 +88,7 @@ public class LwjglCanvasRenderer implements TerasologyCanvasRenderer, PropertyCh private Map> cachedText = Maps.newLinkedHashMap(); private Set usedText = Sets.newHashSet(); - // Texutre mesh caching + // Texture mesh caching private Map cachedTextures = Maps.newLinkedHashMap(); private Set usedTextures = Sets.newHashSet(); diff --git a/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java b/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java index fdfa65ec049..535f627ba88 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java @@ -35,6 +35,7 @@ import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; import org.terasology.engine.GameThread; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; import org.terasology.math.MatrixUtils; import org.terasology.math.geom.Matrix3f; import org.terasology.math.geom.Matrix4f; @@ -56,6 +57,7 @@ public class GLSLMaterial extends BaseMaterial { private static final Logger logger = LoggerFactory.getLogger(GLSLMaterial.class); + private final LwjglGraphicsProcessing graphicsProcessing; private int textureIndex; @@ -69,18 +71,21 @@ public class GLSLMaterial extends BaseMaterial { private EnumSet activeFeatures = Sets.newEnumSet(Collections.emptyList(), ShaderProgramFeature.class); private int activeFeaturesMask; - private final ShaderManager shaderManager; + private ShaderManager shaderManager; private DisposalAction disposalAction; private MaterialData materialData; - public GLSLMaterial(ResourceUrn urn, AssetType assetType, MaterialData data) { + public GLSLMaterial(ResourceUrn urn, AssetType assetType, MaterialData data, LwjglGraphicsProcessing graphicsProcessing) { super(urn, assetType); - disposalAction = new DisposalAction(urn); + this.graphicsProcessing = graphicsProcessing; + disposalAction = new DisposalAction(urn, graphicsProcessing); getDisposalHook().setDisposeAction(disposalAction); this.materialData = data; shaderManager = CoreRegistry.get(ShaderManager.class); - reload(data); + graphicsProcessing.asynchToDisplayThread(() -> { + reload(data); + }); } @Override @@ -143,7 +148,6 @@ public void recompile() { //Some of the uniforms are not updated constantly between frames //this function will rebind any uniforms that are not bound rebindVariables(materialData); - } @Override @@ -156,7 +160,6 @@ public final void doReload(MaterialData data) { shader = (GLSLShader) data.getShader(); recompile(); rebindVariables(data); - }); } catch (InterruptedException e) { logger.error("Failed to reload {}", getUrn(), e); @@ -681,12 +684,14 @@ public int hashCode() { private static class DisposalAction implements Runnable { private final ResourceUrn urn; + private final LwjglGraphicsProcessing graphicsProcessing; private TIntIntMap shaderPrograms = new TIntIntHashMap(); // made package-private after Jenkins' suggestion - DisposalAction(ResourceUrn urn) { + DisposalAction(ResourceUrn urn, LwjglGraphicsProcessing graphicsProcessing) { this.urn = urn; + this.graphicsProcessing = graphicsProcessing; } @Override @@ -694,11 +699,14 @@ public void run() { try { GameThread.synch(() -> { logger.debug("Disposing material {}.", urn); - TIntIntIterator it = shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - GL20.glDeleteProgram(it.value()); - } + final TIntIntMap deletedPrograms = new TIntIntHashMap(shaderPrograms); + graphicsProcessing.asynchToDisplayThread(() -> { + TIntIntIterator it = deletedPrograms.iterator(); + while (it.hasNext()) { + it.advance(); + GL20.glDeleteProgram(it.value()); + } + }); shaderPrograms.clear(); }); } catch (InterruptedException e) { diff --git a/engine/src/main/java/org/terasology/rendering/opengl/GLSLShader.java b/engine/src/main/java/org/terasology/rendering/opengl/GLSLShader.java index f2d4d38354d..386ba5b1487 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/GLSLShader.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/GLSLShader.java @@ -34,6 +34,7 @@ import org.terasology.engine.GameThread; import org.terasology.engine.TerasologyConstants; import org.terasology.engine.paths.PathManager; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.assets.shader.Shader; import org.terasology.rendering.assets.shader.ShaderData; @@ -63,6 +64,7 @@ public class GLSLShader extends Shader { private static final Logger logger = LoggerFactory.getLogger(GLSLShader.class); + private final LwjglGraphicsProcessing graphicsProcessing; // TODO this should be handled another way, we need to get ssao parameters here public int ssaoKernelElements = 32; @@ -98,11 +100,14 @@ public class GLSLShader extends Shader { private DisposalAction disposalAction; - public GLSLShader(ResourceUrn urn, AssetType assetType, ShaderData data) { + public GLSLShader(ResourceUrn urn, AssetType assetType, ShaderData data, LwjglGraphicsProcessing graphicsProcessing) { super(urn, assetType); - disposalAction = new DisposalAction(urn); + this.graphicsProcessing = graphicsProcessing; + disposalAction = new DisposalAction(urn, graphicsProcessing); getDisposalHook().setDisposeAction(disposalAction); - reload(data); + graphicsProcessing.asynchToDisplayThread(() -> { + reload(data); + }); } private static InputStreamReader getInputStreamReaderFromResource(String resource) { @@ -131,6 +136,12 @@ int linkShaderProgram(int featureHash) { @Override public void recompile() { + graphicsProcessing.asynchToDisplayThread(() -> { + recompileInt(); + }); + } + + private void recompileInt() { registerAllShaderPermutations(); // TODO: reload materials } @@ -393,7 +404,7 @@ protected void doReload(ShaderData data) { } updateAvailableFeatures(); try { - recompile(); + recompileInt(); } catch (RuntimeException e) { logger.warn(e.getMessage()); } @@ -406,14 +417,16 @@ protected void doReload(ShaderData data) { private static class DisposalAction implements Runnable { private final ResourceUrn urn; + private final LwjglGraphicsProcessing graphicsProcessing; private final TIntIntMap fragmentPrograms = new TIntIntHashMap(); private final TIntIntMap vertexPrograms = new TIntIntHashMap(); private final TIntIntMap geometryPrograms = new TIntIntHashMap(); // made package-private after CheckStyle's suggestion - DisposalAction(ResourceUrn urn) { + DisposalAction(ResourceUrn urn, LwjglGraphicsProcessing graphicsProcessing) { this.urn = urn; + this.graphicsProcessing = graphicsProcessing; } @Override @@ -433,11 +446,14 @@ private void disposeData() { } private void disposePrograms(TIntIntMap programs) { - TIntIntIterator it = programs.iterator(); - while (it.hasNext()) { - it.advance(); - GL20.glDeleteShader(it.value()); - } + final TIntIntMap disposedPrograms = new TIntIntHashMap(programs); + graphicsProcessing.asynchToDisplayThread(() -> { + TIntIntIterator it = disposedPrograms.iterator(); + while (it.hasNext()) { + it.advance(); + GL20.glDeleteShader(it.value()); + } + }); programs.clear(); } } diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java index a85c14d1878..352bb9ad253 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java @@ -31,6 +31,7 @@ import org.terasology.assets.ResourceUrn; import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; import org.terasology.math.AABB; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.mesh.Mesh; @@ -77,10 +78,12 @@ public class OpenGLMesh extends Mesh { private DisposalAction disposalAction; - public OpenGLMesh(ResourceUrn urn, AssetType assetType, GLBufferPool bufferPool, MeshData data) { + public OpenGLMesh(ResourceUrn urn, AssetType assetType, GLBufferPool bufferPool, MeshData data, LwjglGraphicsProcessing graphicsProcessing) { super(urn, assetType); this.disposalAction = new DisposalAction(urn, bufferPool); - reload(data); + graphicsProcessing.asynchToDisplayThread(() -> { + reload(data); + }); } @Override @@ -291,6 +294,4 @@ public void run() { } } } - - } diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java index fc4a14dbb55..c04ccd5cc28 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java @@ -28,6 +28,7 @@ import org.terasology.assets.ResourceUrn; import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; import org.terasology.math.AABB; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.skeletalmesh.Bone; @@ -68,11 +69,14 @@ public class OpenGLSkeletalMesh extends SkeletalMesh { private DisposalAction disposalAction; - public OpenGLSkeletalMesh(ResourceUrn urn, AssetType assetType, SkeletalMeshData data, GLBufferPool bufferPool) { + public OpenGLSkeletalMesh(ResourceUrn urn, AssetType assetType, GLBufferPool bufferPool, + SkeletalMeshData data, LwjglGraphicsProcessing graphicsProcessing) { super(urn, assetType); disposalAction = new DisposalAction(urn, bufferPool); getDisposalHook().setDisposeAction(disposalAction); - reload(data); + graphicsProcessing.asynchToDisplayThread(() -> { + reload(data); + }); } public void setScaleTranslate(org.joml.Vector3f newScale, org.joml.Vector3f newTranslate) { diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java index 438c6976ea8..fc44640382f 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java @@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.engine.subsystem.lwjgl.LwjglGraphics; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsManager; import org.terasology.math.JomlUtil; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.assets.texture.TextureData; @@ -39,7 +39,7 @@ public class OpenGLTexture extends Texture { private final TextureResources resources; - public OpenGLTexture(ResourceUrn urn, AssetType assetType, TextureData data, LwjglGraphics graphicsManager) { + public OpenGLTexture(ResourceUrn urn, AssetType assetType, TextureData data, LwjglGraphicsManager graphicsManager) { super(urn, assetType); this.resources = new TextureResources(graphicsManager); getDisposalHook().setDisposeAction(resources); @@ -249,13 +249,13 @@ public TextureData getTextureData() { private static class TextureResources implements Runnable { - private final LwjglGraphics graphicsManager; + private final LwjglGraphicsManager graphicsManager; private volatile int id; private volatile LoadedTextureInfo loadedTextureInfo; private final List disposalSubscribers = Lists.newArrayList(); - TextureResources(LwjglGraphics graphicsManager) { + TextureResources(LwjglGraphicsManager graphicsManager) { this.graphicsManager = graphicsManager; } diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java index 30984425b38..55f66d06917 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java @@ -26,7 +26,7 @@ import org.terasology.engine.module.rendering.RenderingModuleRegistry; import org.terasology.engine.subsystem.DisplayDevice; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; -import org.terasology.engine.subsystem.lwjgl.LwjglGraphics; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsUtil; import org.terasology.logic.console.Console; import org.terasology.logic.console.commandSystem.MethodCommand; import org.terasology.logic.console.commandSystem.annotations.Command; @@ -365,7 +365,7 @@ public void render(RenderingStage renderingStage) { renderPipelineTaskList.forEach(RenderPipelineTask::process); // this line re-establish Terasology defaults, so that the rest of the application can rely on them. - LwjglGraphics.initOpenGLParams(); + LwjglGraphicsUtil.initOpenGLParams(); playerCamera.updatePrevViewProjectionMatrix(); } diff --git a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java index 270694446b7..9059fdedd84 100644 --- a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java @@ -21,7 +21,6 @@ import org.terasology.math.geom.Rect2f; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; -import org.terasology.math.geom.Vector4f; import org.terasology.module.sandbox.API; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.assets.material.Material; diff --git a/engine/src/main/java/org/terasology/telemetry/metrics/SystemContextMetric.java b/engine/src/main/java/org/terasology/telemetry/metrics/SystemContextMetric.java index cc03c54314b..8bf79a4ba9c 100644 --- a/engine/src/main/java/org/terasology/telemetry/metrics/SystemContextMetric.java +++ b/engine/src/main/java/org/terasology/telemetry/metrics/SystemContextMetric.java @@ -16,10 +16,10 @@ package org.terasology.telemetry.metrics; import com.snowplowanalytics.snowplow.tracker.events.Unstructured; -import org.lwjgl.opengl.GL11; import org.terasology.config.Config; import org.terasology.context.Context; import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.DisplayDeviceInfo; import org.terasology.registry.CoreRegistry; import org.terasology.telemetry.TelemetryCategory; import org.terasology.telemetry.TelemetryField; @@ -88,15 +88,10 @@ public SystemContextMetric(Context context) { jvmVersion = System.getProperty("java.vm.version"); contextInCoreRegistry = CoreRegistry.get(Context.class); DisplayDevice display = contextInCoreRegistry.get(DisplayDevice.class); - if (!display.isHeadless()) { - openGLVendor = GL11.glGetString(GL11.GL_VENDOR); - openGLVersion = GL11.glGetString(GL11.GL_VERSION); - openGLRenderer = GL11.glGetString(GL11.GL_RENDERER); - } else { - openGLVendor = "headless"; - openGLVersion = "headless"; - openGLRenderer = "headless"; - } + DisplayDeviceInfo displayDeviceInfo = display.getInfo(); + openGLVendor = displayDeviceInfo.getOpenGlVendor(); + openGLVersion = displayDeviceInfo.getOpenGLVersion(); + openGLRenderer = displayDeviceInfo.getOpenGLRenderer(); processorNumbers = Runtime.getRuntime().availableProcessors(); memoryMaxByte = Runtime.getRuntime().maxMemory(); } diff --git a/facades/TeraEd/build.gradle b/facades/TeraEd/build.gradle index be43aefd617..02924c76afb 100644 --- a/facades/TeraEd/build.gradle +++ b/facades/TeraEd/build.gradle @@ -28,6 +28,26 @@ dependencies { implementation group: 'org.reflections', name: 'reflections', version: '0.9.10' runtimeOnly(platform(project(":modules"))) + // For the "natives" configuration make it depend on the native files from LWJGL + implementation platform("org.lwjgl:lwjgl-bom:$LwjglVersion") + ["natives-linux", "natives-windows", "natives-macos"].forEach { + implementation "org.lwjgl:lwjgl::$it" + implementation "org.lwjgl:lwjgl-assimp::$it" + implementation "org.lwjgl:lwjgl-glfw::$it" + implementation "org.lwjgl:lwjgl-openal::$it" + implementation "org.lwjgl:lwjgl-opengl::$it" + implementation "org.lwjgl:lwjgl-stb::$it" + } + implementation "org.lwjgl:lwjgl-jawt" + + implementation(group: 'com.google.guava', name: 'guava', version: '23.0') + + implementation(project(":subsystems:DiscordRPC")) + implementation(project(":subsystems:TypeHandlerLibrary")) + + implementation(group: 'org.lwjglx', name: 'lwjgl3-awt', version: '0.1.7') { + exclude group: 'org.lwjgl', module: '' + } } application { @@ -42,7 +62,7 @@ run { args "-homedir" } -task editor(type:JavaExec) { +task editor(type: JavaExec) { description = "Run 'TeraEd' to configure graphics shader parameters in a standard PC application" group = "terasology run" diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/TeraEd.java b/facades/TeraEd/src/main/java/org/terasology/editor/TeraEd.java index ba7c7f25973..36114085413 100644 --- a/facades/TeraEd/src/main/java/org/terasology/editor/TeraEd.java +++ b/facades/TeraEd/src/main/java/org/terasology/editor/TeraEd.java @@ -1,39 +1,30 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.editor; +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 -import javax.swing.JPopupMenu; -import javax.swing.JWindow; -import javax.swing.UIManager; +package org.terasology.editor; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.awt.AWTGLCanvas; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.editor.properties.SceneProperties; +import org.terasology.editor.subsystem.AwtInput; +import org.terasology.editor.subsystem.LwjglPortlet; import org.terasology.editor.ui.MainWindow; import org.terasology.engine.GameEngine; import org.terasology.engine.TerasologyEngine; import org.terasology.engine.TerasologyEngineBuilder; import org.terasology.engine.modes.StateMainMenu; import org.terasology.engine.paths.PathManager; +import org.terasology.engine.subsystem.config.BindsSubsystem; import org.terasology.engine.subsystem.lwjgl.LwjglAudio; -import org.terasology.engine.subsystem.lwjgl.LwjglGraphics; -import org.terasology.engine.subsystem.lwjgl.LwjglInput; -import org.terasology.engine.subsystem.lwjgl.LwjglPortlet; import org.terasology.engine.subsystem.lwjgl.LwjglTimer; +import org.terasology.monitoring.PerformanceMonitor; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; /** * TeraEd main class. @@ -65,24 +56,49 @@ public void run() { // If Nimbus is not available, you can set the GUI to another look and feel. logger.warn("Failed to set look and feel to Nimbus", e); } + try { - LwjglPortlet lwjglPortlet = new LwjglPortlet(); + LwjglPortlet portlet = new LwjglPortlet(); PathManager.getInstance().useDefaultHomePath(); engine = new TerasologyEngineBuilder() - .add(new LwjglGraphics()) .add(new LwjglTimer()) .add(new LwjglAudio()) - .add(new LwjglInput()) - .add(lwjglPortlet).build(); + .add(new AwtInput()) + .add(new BindsSubsystem()) + .add(portlet).build(); + + if (!GLFW.glfwInit()) { + throw new RuntimeException("Failed to initialize GLFW"); + } sceneProperties = new SceneProperties(engine); + mainWindow = new MainWindow(this, engine); - lwjglPortlet.setCustomViewport(mainWindow.getViewport()); + portlet.createCanvas(); + AWTGLCanvas canvas = portlet.getCanvas(); engine.subscribeToStateChange(mainWindow); + engine.initializeRun(new StateMainMenu()); + + mainWindow.getViewport().setTerasology(canvas); + + portlet.initInputs(); + + Runnable renderLoop = new Runnable() { + public void run() { + if (canvas.isValid()) { + canvas.render(); + } + SwingUtilities.invokeLater(this); + } + }; - engine.run(new StateMainMenu()); + // Setup swing thread as game thread + PerformanceMonitor.startActivity("Other"); + SwingUtilities.invokeAndWait(portlet::setupThreads); + SwingUtilities.invokeLater(renderLoop); + PerformanceMonitor.endActivity(); } catch (Throwable t) { logger.error("Uncaught Exception", t); } diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtKeyboardDevice.java b/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtKeyboardDevice.java new file mode 100644 index 00000000000..46f50b395ff --- /dev/null +++ b/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtKeyboardDevice.java @@ -0,0 +1,264 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.editor.input; + +import com.google.common.collect.Lists; +import gnu.trove.map.TIntIntMap; +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntIntHashMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; +import org.lwjgl.opengl.awt.AWTGLCanvas; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.input.ButtonState; +import org.terasology.input.Input; +import org.terasology.input.InputType; +import org.terasology.input.Keyboard; +import org.terasology.input.device.CharKeyboardAction; +import org.terasology.input.device.KeyboardDevice; +import org.terasology.input.device.RawKeyboardAction; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Queue; + +/** + * AWT converting keyboard device representation. + */ +public class AwtKeyboardDevice implements KeyboardDevice { + + private static final Logger logger = LoggerFactory.getLogger(AwtKeyboardDevice.class); + private static final TIntIntMap AWT_TO_TERA_MAPPING = new TIntIntHashMap(); + private static final TIntObjectMap AWT_TO_TERA_EXTRA = new TIntObjectHashMap<>(); + + static { + //TODO: test and cleanup keys +// AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NONE, Keyboard.KeyId.NONE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_ESCAPE, Keyboard.KeyId.ESCAPE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_1, Keyboard.KeyId.KEY_1); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_2, Keyboard.KeyId.KEY_2); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_3, Keyboard.KeyId.KEY_3); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_4, Keyboard.KeyId.KEY_4); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_5, Keyboard.KeyId.KEY_5); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_6, Keyboard.KeyId.KEY_6); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_7, Keyboard.KeyId.KEY_7); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_8, Keyboard.KeyId.KEY_8); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_9, Keyboard.KeyId.KEY_9); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_0, Keyboard.KeyId.KEY_0); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_MINUS, Keyboard.KeyId.MINUS); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_BACK_SPACE, Keyboard.KeyId.BACKSPACE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_TAB, Keyboard.KeyId.TAB); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_Q, Keyboard.KeyId.Q); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_W, Keyboard.KeyId.W); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_E, Keyboard.KeyId.E); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_R, Keyboard.KeyId.R); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_T, Keyboard.KeyId.T); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_Y, Keyboard.KeyId.Y); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_U, Keyboard.KeyId.U); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_I, Keyboard.KeyId.I); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_O, Keyboard.KeyId.O); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_P, Keyboard.KeyId.P); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_OPEN_BRACKET, Keyboard.KeyId.LEFT_BRACKET); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_CLOSE_BRACKET, Keyboard.KeyId.RIGHT_BRACKET); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_A, Keyboard.KeyId.A); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_S, Keyboard.KeyId.S); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_D, Keyboard.KeyId.D); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F, Keyboard.KeyId.F); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_G, Keyboard.KeyId.G); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_H, Keyboard.KeyId.H); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_J, Keyboard.KeyId.J); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_K, Keyboard.KeyId.K); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_L, Keyboard.KeyId.L); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_SEMICOLON, Keyboard.KeyId.SEMICOLON); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DEAD_ACUTE, Keyboard.KeyId.APOSTROPHE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DEAD_GRAVE, Keyboard.KeyId.GRAVE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_BACK_SLASH, Keyboard.KeyId.BACKSLASH); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_Z, Keyboard.KeyId.Z); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_X, Keyboard.KeyId.X); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_C, Keyboard.KeyId.C); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_V, Keyboard.KeyId.V); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_B, Keyboard.KeyId.B); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_N, Keyboard.KeyId.N); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_M, Keyboard.KeyId.M); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_COMMA, Keyboard.KeyId.COMMA); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_PERIOD, Keyboard.KeyId.PERIOD); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_SLASH, Keyboard.KeyId.SLASH); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_MULTIPLY, Keyboard.KeyId.NUMPAD_MULTIPLY); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_SPACE, Keyboard.KeyId.SPACE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_CAPS_LOCK, Keyboard.KeyId.CAPS_LOCK); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F1, Keyboard.KeyId.F1); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F2, Keyboard.KeyId.F2); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F3, Keyboard.KeyId.F3); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F4, Keyboard.KeyId.F4); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F5, Keyboard.KeyId.F5); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F6, Keyboard.KeyId.F6); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F7, Keyboard.KeyId.F7); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F8, Keyboard.KeyId.F8); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F9, Keyboard.KeyId.F9); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F10, Keyboard.KeyId.F10); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUM_LOCK, Keyboard.KeyId.NUM_LOCK); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_SCROLL_LOCK, Keyboard.KeyId.SCROLL_LOCK); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD7, Keyboard.KeyId.NUMPAD_7); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD8, Keyboard.KeyId.NUMPAD_8); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD9, Keyboard.KeyId.NUMPAD_9); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_SUBTRACT, Keyboard.KeyId.NUMPAD_MINUS); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD4, Keyboard.KeyId.NUMPAD_4); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD5, Keyboard.KeyId.NUMPAD_5); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD6, Keyboard.KeyId.NUMPAD_6); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_ADD, Keyboard.KeyId.NUMPAD_PLUS); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD1, Keyboard.KeyId.NUMPAD_1); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD2, Keyboard.KeyId.NUMPAD_2); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD3, Keyboard.KeyId.NUMPAD_3); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_NUMPAD0, Keyboard.KeyId.NUMPAD_0); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DECIMAL, Keyboard.KeyId.NUMPAD_PERIOD); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F11, Keyboard.KeyId.F11); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F12, Keyboard.KeyId.F12); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F13, Keyboard.KeyId.F13); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F14, Keyboard.KeyId.F14); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F15, Keyboard.KeyId.F15); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F16, Keyboard.KeyId.F16); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F17, Keyboard.KeyId.F17); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F18, Keyboard.KeyId.F18); +// glfwToTeraMaps.put(KeyEvent.VK_KANA, Keyboard.KeyId.KANA); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_F19, Keyboard.KeyId.F19); +// glfwToTeraMaps.put(KeyEvent.VK_CONVERT, Keyboard.KeyId.CONVERT); +// glfwToTeraMaps.put(KeyEvent.VK_NOCONVERT, Keyboard.KeyId.NOCONVERT); +// glfwToTeraMaps.put(KeyEvent.VK_YEN, Keyboard.KeyId.YEN); + +// glfwToTeraMaps.put(KeyEvent.VK_CIRCUMFLEX, Keyboard.KeyId.CIRCUMFLEX); +// glfwToTeraMaps.put(KeyEvent.VK_AT, Keyboard.KeyId.AT); +// glfwToTeraMaps.put(KeyEvent.VK_COLON, Keyboard.KeyId.COLON); +// glfwToTeraMaps.put(KeyEvent.VK_UNDERLINE, Keyboard.KeyId.UNDERLINE); +// glfwToTeraMaps.put(KeyEvent.VK_KANJI, Keyboard.KeyId.KANJI); +// glfwToTeraMaps.put(KeyEvent.VK_STOP, Keyboard.KeyId.STOP); +// glfwToTeraMaps.put(KeyEvent.VK_AX, Keyboard.KeyId.AX); +// glfwToTeraMaps.put(KeyEvent.VK_UNLABELED, Keyboard.KeyId.UNLABELED); + +// glfwToTeraMaps.put(KeyEvent.VK_SECTION, Keyboard.KeyId.SECTION); +// glfwToTeraMaps.put(KeyEvent.VK_KP_COMMA, Keyboard.KeyId.NUMPAD_COMMA); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DIVIDE, Keyboard.KeyId.NUMPAD_DIVIDE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_PRINTSCREEN, Keyboard.KeyId.PRINT_SCREEN); + +// glfwToTeraMaps.put(KeyEvent.VK_FUNCTION, Keyboard.KeyId.FUNCTION); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_PAUSE, Keyboard.KeyId.PAUSE); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_HOME, Keyboard.KeyId.HOME); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_UP, Keyboard.KeyId.UP); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_PAGE_UP, Keyboard.KeyId.PAGE_UP); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_LEFT, Keyboard.KeyId.LEFT); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_RIGHT, Keyboard.KeyId.RIGHT); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_END, Keyboard.KeyId.END); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DOWN, Keyboard.KeyId.DOWN); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_PAGE_DOWN, Keyboard.KeyId.PAGE_DOWN); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_INSERT, Keyboard.KeyId.INSERT); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_DELETE, Keyboard.KeyId.DELETE); +// glfwToTeraMaps.put(KeyEvent.VK_CLEAR, Keyboard.KeyId.CLEAR); + AWT_TO_TERA_MAPPING.put(KeyEvent.VK_META, Keyboard.KeyId.LEFT_META); +// AWT_TO_TERA_MAPPING.put(KeyEvent.VK_RIGHT_SUPER, Keyboard.KeyId.RIGHT_META); +// glfwToTeraMaps.put(KeyEvent.VK_APPS, Keyboard.KeyId.APPS); +// glfwToTeraMaps.put(KeyEvent.VK_POWER, Keyboard.KeyId.POWER); +// glfwToTeraMaps.put(KeyEvent.VK_SLEEP, Keyboard.KeyId.SLEEP); + + TIntIntHashMap controlMap = new TIntIntHashMap(); + controlMap.put(KeyEvent.KEY_LOCATION_LEFT, Keyboard.KeyId.LEFT_CTRL); + controlMap.put(KeyEvent.KEY_LOCATION_RIGHT, Keyboard.KeyId.RIGHT_CTRL); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_CONTROL, controlMap); + TIntIntHashMap shiftMap = new TIntIntHashMap(); + shiftMap.put(KeyEvent.KEY_LOCATION_LEFT, Keyboard.KeyId.LEFT_SHIFT); + shiftMap.put(KeyEvent.KEY_LOCATION_RIGHT, Keyboard.KeyId.RIGHT_SHIFT); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_SHIFT, shiftMap); + TIntIntHashMap altMap = new TIntIntHashMap(); + altMap.put(KeyEvent.KEY_LOCATION_LEFT, Keyboard.KeyId.LEFT_ALT); + altMap.put(KeyEvent.KEY_LOCATION_RIGHT, Keyboard.KeyId.RIGHT_ALT); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_ALT, altMap); + TIntIntHashMap metaMap = new TIntIntHashMap(); + metaMap.put(KeyEvent.KEY_LOCATION_LEFT, Keyboard.KeyId.LEFT_META); + metaMap.put(KeyEvent.KEY_LOCATION_RIGHT, Keyboard.KeyId.RIGHT_META); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_META, metaMap); + TIntIntHashMap equalsMap = new TIntIntHashMap(); + equalsMap.put(KeyEvent.KEY_LOCATION_NUMPAD, Keyboard.KeyId.NUMPAD_EQUALS); + equalsMap.put(KeyEvent.KEY_LOCATION_STANDARD, Keyboard.KeyId.EQUALS); + equalsMap.put(KeyEvent.KEY_LOCATION_UNKNOWN, Keyboard.KeyId.EQUALS); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_EQUALS, equalsMap); + TIntIntHashMap enterMap = new TIntIntHashMap(); + enterMap.put(KeyEvent.KEY_LOCATION_NUMPAD, Keyboard.KeyId.NUMPAD_ENTER); + enterMap.put(KeyEvent.KEY_LOCATION_STANDARD, Keyboard.KeyId.ENTER); + enterMap.put(KeyEvent.KEY_LOCATION_UNKNOWN, Keyboard.KeyId.ENTER); + AWT_TO_TERA_EXTRA.put(KeyEvent.VK_ENTER, enterMap); + } + + private Queue rawKeyQueue = Lists.newLinkedList(); + private Queue charQueue = Lists.newLinkedList(); + private TIntSet buttonStates = new TIntHashSet(); + + public AwtKeyboardDevice() { + } + + public void registerToAwtGlCanvas(AWTGLCanvas canvas) { + canvas.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + charQueue.offer(new CharKeyboardAction(e.getKeyChar())); + } + + @Override + public void keyPressed(KeyEvent e) { + awtKeyCallback(e.getExtendedKeyCode(), ButtonState.DOWN, e.getKeyLocation()); + } + + @Override + public void keyReleased(KeyEvent e) { + awtKeyCallback(e.getExtendedKeyCode(), ButtonState.UP, e.getKeyLocation()); + } + }); + } + + /** + * Callback receive key input events. + */ + public void awtKeyCallback(int key, ButtonState state, int location) { + int teraKey; + TIntIntHashMap extraMap = AWT_TO_TERA_EXTRA.get(key); + if (extraMap != null) { + teraKey = extraMap.get(key); + } else { + teraKey = AWT_TO_TERA_MAPPING.get(key); + } + Input input = InputType.KEY.getInput(teraKey); + + if (state == ButtonState.DOWN) { + buttonStates.add(teraKey); + } else if (state == ButtonState.UP) { + buttonStates.remove(teraKey); + } + + rawKeyQueue.offer(new RawKeyboardAction(input, state)); + } + + @Override + public boolean isKeyDown(int key) { + return buttonStates.contains(key); + } + + @Override + public Queue getInputQueue() { + Queue rawKeyboardActions = Lists.newLinkedList(); + RawKeyboardAction action; + while ((action = rawKeyQueue.poll()) != null) { + rawKeyboardActions.add(action); + } + return rawKeyboardActions; + } + + @Override + public Queue getCharInputQueue() { + Queue charActions = Lists.newLinkedList(); + CharKeyboardAction action; + while ((action = charQueue.poll()) != null) { + charActions.add(action); + } + return charActions; + } +} diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtMouseDevice.java b/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtMouseDevice.java new file mode 100644 index 00000000000..482bbd19571 --- /dev/null +++ b/facades/TeraEd/src/main/java/org/terasology/editor/input/AwtMouseDevice.java @@ -0,0 +1,164 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.editor.input; + +import com.google.common.collect.Lists; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; +import org.joml.Vector2d; +import org.joml.Vector2i; +import org.lwjgl.opengl.awt.AWTGLCanvas; +import org.terasology.config.RenderingConfig; +import org.terasology.input.ButtonState; +import org.terasology.input.InputType; +import org.terasology.input.MouseInput; +import org.terasology.input.device.MouseAction; +import org.terasology.input.device.MouseDevice; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Queue; + +/** + * Awt mouse device convertor. Handles mouse input via AWT's callbacks Handles mouse state. + */ +public class AwtMouseDevice implements MouseDevice, PropertyChangeListener { + private RenderingConfig renderingConfig; + private float uiScale; + private boolean mouseGrabbed; + private Queue queue = Lists.newLinkedList(); + + private TIntSet buttonStates = new TIntHashSet(); + + private double xPos; + private double yPos; + + private double xPosDelta; + private double yPosDelta; + + public AwtMouseDevice(RenderingConfig renderingConfig) { + this.renderingConfig = renderingConfig; + this.uiScale = renderingConfig.getUiScale() / 100f; + renderingConfig.subscribe(RenderingConfig.UI_SCALE, this); + } + + public void registerToAwtGlCanvas(AWTGLCanvas canvas) { + canvas.addMouseListener(new MouseListener() { + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mousePressed(MouseEvent e) { + int button = e.getButton() - 1; + buttonStates.add(button); + MouseInput mouseInput = MouseInput.find(InputType.MOUSE_BUTTON, button); + queue.offer(new MouseAction(mouseInput, ButtonState.DOWN, getPosition())); + } + + @Override + public void mouseReleased(MouseEvent e) { + int button = e.getButton() - 1; + buttonStates.remove(button); + MouseInput mouseInput = MouseInput.find(InputType.MOUSE_BUTTON, button); + queue.offer(new MouseAction(mouseInput, ButtonState.UP, getPosition())); + } + + @Override + public void mouseEntered(MouseEvent e) { + + } + + @Override + public void mouseExited(MouseEvent e) { + + } + }); + canvas.addMouseMotionListener(new MouseMotionListener() { + @Override + public void mouseDragged(MouseEvent e) { + updateMouse(e.getX(), e.getY()); + } + + @Override + public void mouseMoved(MouseEvent e) { + updateMouse(e.getX(), e.getY()); + } + }); + + canvas.addMouseWheelListener(e -> { + int yOffset = e.getUnitsToScroll(); + if (yOffset != 0.0) { + int id = (yOffset > 0) ? 1 : -1; + queue.offer(new MouseAction(InputType.MOUSE_WHEEL.getInput(id), 1, getPosition())); + } + }); + } + + @Override + public void update() { + } + + private void updateMouse(double x, double y) { + xPosDelta = x - this.xPos; + yPosDelta = y - this.yPos; + this.xPos = x; + this.yPos = y; + } + + @Override + public Vector2i getPosition() { + return new Vector2i((int) (xPos / this.uiScale), (int) (yPos / this.uiScale)); + } + + @Override + public Vector2d getDelta() { + + Vector2d result = new Vector2d(xPosDelta, yPosDelta); + return result; + } + + @Override + public boolean isButtonDown(int button) { + return buttonStates.contains(button); + } + + @Override + public boolean isVisible() { + return !mouseGrabbed; + } + + @Override + public void setGrabbed(boolean newGrabbed) { + if (newGrabbed != mouseGrabbed) { + mouseGrabbed = newGrabbed; + // TODO handle swing mouse grabbing + } + } + + @Override + public Queue getInputQueue() { + Queue mouseActions = Lists.newLinkedList(); + MouseAction action; + while ((action = queue.poll()) != null) { + mouseActions.add(action); + } + return mouseActions; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(RenderingConfig.UI_SCALE)) { + this.uiScale = this.renderingConfig.getUiScale() / 100f; + } + } + + public void resetDelta() { + xPosDelta = 0; + yPosDelta = 0; + } +} diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/AwtInput.java b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/AwtInput.java new file mode 100644 index 00000000000..33c74501541 --- /dev/null +++ b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/AwtInput.java @@ -0,0 +1,60 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.editor.subsystem; + +import org.terasology.assets.module.ModuleAwareAssetTypeManager; +import org.terasology.config.Config; +import org.terasology.config.ControllerConfig; +import org.terasology.context.Context; +import org.terasology.editor.input.AwtKeyboardDevice; +import org.terasology.editor.input.AwtMouseDevice; +import org.terasology.engine.modes.GameState; +import org.terasology.engine.subsystem.config.BindsManager; +import org.terasology.engine.subsystem.lwjgl.BaseLwjglSubsystem; +import org.terasology.input.InputSystem; +import org.terasology.input.lwjgl.LwjglControllerDevice; + +public class AwtInput extends BaseLwjglSubsystem { + + private Context context; + + @Override + public String getName() { + return "Input"; + } + + @Override + public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { + } + + @Override + public void postInitialise(Context rootContext) { + this.context = rootContext; + initControls(); + updateInputConfig(); + } + + @Override + public void postUpdate(GameState currentState, float delta) { + currentState.handleInput(delta); + } + + private void initControls() { + Config config = context.get(Config.class); + + InputSystem inputSystem = new InputSystem(); + context.put(InputSystem.class, inputSystem); + inputSystem.setMouseDevice(new AwtMouseDevice(config.getRendering())); + inputSystem.setKeyboardDevice(new AwtKeyboardDevice()); + + ControllerConfig controllerConfig = config.getInput().getControllers(); + LwjglControllerDevice controllerDevice = new LwjglControllerDevice(controllerConfig); + inputSystem.setControllerDevice(controllerDevice); + } + + private void updateInputConfig() { + BindsManager bindsManager = context.get(BindsManager.class); + bindsManager.updateConfigWithDefaultBinds(); + bindsManager.saveBindsConfig(); + } +} diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortlet.java b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortlet.java new file mode 100644 index 00000000000..e247966dd6d --- /dev/null +++ b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortlet.java @@ -0,0 +1,219 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.editor.subsystem; + +import com.google.common.base.Preconditions; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.opengl.GL43; +import org.lwjgl.opengl.awt.AWTGLCanvas; +import org.lwjgl.opengl.awt.GLData; +import org.lwjgl.system.MemoryUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.assets.module.ModuleAwareAssetTypeManager; +import org.terasology.config.Config; +import org.terasology.config.RenderingConfig; +import org.terasology.context.Context; +import org.terasology.editor.input.AwtKeyboardDevice; +import org.terasology.editor.input.AwtMouseDevice; +import org.terasology.engine.GameEngine; +import org.terasology.engine.GameThread; +import org.terasology.engine.TerasologyEngine; +import org.terasology.engine.modes.GameState; +import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.lwjgl.BaseLwjglSubsystem; +import org.terasology.engine.subsystem.lwjgl.DebugCallback; +import org.terasology.engine.subsystem.lwjgl.GLFWErrorCallback; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsManager; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsUtil; +import org.terasology.entitySystem.event.internal.EventSystem; +import org.terasology.input.InputSystem; +import org.terasology.nui.canvas.CanvasRenderer; +import org.terasology.registry.CoreRegistry; +import org.terasology.rendering.ShaderManager; +import org.terasology.rendering.ShaderManagerLwjgl; +import org.terasology.rendering.nui.internal.LwjglCanvasRenderer; +import org.terasology.rendering.world.WorldRenderer; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; + +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.glClear; +import static org.lwjgl.opengl.GL11.glLoadIdentity; + +public class LwjglPortlet extends BaseLwjglSubsystem { + + private static final Logger logger = LoggerFactory.getLogger(LwjglPortlet.class); + + private Context context; + private RenderingConfig config; + + private GameEngine engine; + private AWTGLCanvas canvas; + private LwjglPortletDisplayDevice display; + private AwtMouseDevice mouseDevice; + + private final LwjglGraphicsManager graphics = new LwjglGraphicsManager(); + + @Override + public String getName() { + return "Portlet"; + } + + @Override + public void initialise(GameEngine gameEngine, Context rootContext) { + logger.info("Starting initialization of LWJGL"); + this.engine = gameEngine; + this.context = rootContext; + this.config = context.get(Config.class).getRendering(); + + graphics.setThreadMode(LwjglGraphicsManager.ThreadMode.DISPLAY_THREAD); + display = new LwjglPortletDisplayDevice(canvas, graphics); + context.put(DisplayDevice.class, display); + logger.info("Initial initialization complete"); + } + + @Override + public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager) { + graphics.registerCoreAssetTypes(assetTypeManager); + } + + @Override + public void postInitialise(Context rootContext) { + graphics.registerRenderingSubsystem(context); + + initBuffer(); + + context.put(ShaderManager.class, new ShaderManagerLwjgl()); + context.put(CanvasRenderer.class, new LwjglCanvasRenderer(context)); + } + + @Override + public void postUpdate(GameState currentState, float delta) { + graphics.processActions(); + + currentState.render(); + + display.update(); + int frameLimit = context.get(Config.class).getRendering().getFrameLimit(); + if (frameLimit > 0) { +// Lwjgl2Sync.sync(frameLimit); + } + if (display.isCloseRequested()) { + engine.shutdown(); + } + } + + public void setupThreads() { + GameThread.reset(); + GameThread.setToCurrentThread(); + graphics.setThreadMode(LwjglGraphicsManager.ThreadMode.GAME_THREAD); + + EventSystem eventSystem = CoreRegistry.get(EventSystem.class); + if (eventSystem != null) { + eventSystem.setToCurrentThread(); + } + } + + public void createCanvas() { + GLData data = new GLData(); + data.samples = 4; + canvas = new AWTGLCanvas() { + @Override + public void initGL() { + initGLFW(); + initOpenGL(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + } + + @Override + public void paintGL() { + if (((TerasologyEngine) engine).tick()) { + mouseDevice.resetDelta(); + } + } + }; + } + + public AWTGLCanvas getCanvas() { + return this.canvas; + } + + private void initGLFW() { + if (!GLFW.glfwInit()) { + throw new RuntimeException("Failed to initialize GLFW"); + } + + GLFW.glfwDefaultWindowHints(); + GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE); + GLFW.glfwWindowHint(GLFW.GLFW_COCOA_GRAPHICS_SWITCHING, GLFW.GLFW_TRUE); + GLFW.glfwWindowHint(GLFW.GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW.GLFW_FALSE); + GLFW.glfwWindowHint(GLFW.GLFW_DEPTH_BITS, config.getPixelFormat()); + + if (config.getDebug().isEnabled()) { + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); + } + + GLFW.glfwSetErrorCallback(new GLFWErrorCallback()); + } + + private void initBuffer() { + logger.info("Initializing display (if last line in log then likely the game crashed from an issue with your " + + "video card)"); + + if (!config.isVSync()) { + GLFW.glfwSwapInterval(0); + } + + try { + String root = "org/terasology/icons/"; + ClassLoader classLoader = getClass().getClassLoader(); + + BufferedImage icon16 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_16.png")); + BufferedImage icon32 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_32.png")); + BufferedImage icon64 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_64.png")); + BufferedImage icon128 = ImageIO.read(classLoader.getResourceAsStream(root + "gooey_sweet_128.png")); + GLFWImage.Buffer buffer = GLFWImage.create(4); + buffer.put(0, LwjglGraphicsUtil.convertToGLFWFormat(icon16)); + buffer.put(1, LwjglGraphicsUtil.convertToGLFWFormat(icon32)); + buffer.put(2, LwjglGraphicsUtil.convertToGLFWFormat(icon64)); + buffer.put(3, LwjglGraphicsUtil.convertToGLFWFormat(icon128)); + + } catch (IOException | IllegalArgumentException e) { + logger.warn("Could not set icon", e); + } + + display.setDisplayModeSetting(config.getDisplayModeSetting()); + } + + private void initOpenGL() { + logger.info("Initializing OpenGL"); + LwjglGraphicsUtil.checkOpenGL(); + LwjglGraphicsUtil.initOpenGLParams(); + if (config.getDebug().isEnabled()) { + try { + GL43.glDebugMessageCallback(new DebugCallback(), MemoryUtil.NULL); + } catch (IllegalStateException e) { + logger.warn("Unable to specify DebugCallback to receive debugging messages from the GL."); + } + } + } + + public void initInputs() { + final InputSystem inputSystem = context.get(InputSystem.class); + Preconditions.checkNotNull(inputSystem); + mouseDevice = ((AwtMouseDevice) inputSystem.getMouseDevice()); + mouseDevice.registerToAwtGlCanvas(canvas); + ((AwtKeyboardDevice) inputSystem.getKeyboard()).registerToAwtGlCanvas(canvas); + } + + @Override + public void shutdown() { + GLFW.glfwTerminate(); + } +} diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortletDisplayDevice.java b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortletDisplayDevice.java new file mode 100644 index 00000000000..b0bc69f2bf5 --- /dev/null +++ b/facades/TeraEd/src/main/java/org/terasology/editor/subsystem/LwjglPortletDisplayDevice.java @@ -0,0 +1,130 @@ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.editor.subsystem; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.awt.AWTGLCanvas; +import org.terasology.engine.subsystem.DisplayDevice; +import org.terasology.engine.subsystem.DisplayDeviceInfo; +import org.terasology.engine.subsystem.Resolution; +import org.terasology.engine.subsystem.lwjgl.LwjglDisplayDevice; +import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsManager; +import org.terasology.engine.subsystem.lwjgl.LwjglResolution; +import org.terasology.rendering.nui.layers.mainMenu.videoSettings.DisplayModeSetting; +import org.terasology.utilities.subscribables.AbstractSubscribable; + +import java.awt.GraphicsEnvironment; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.List; + +public class LwjglPortletDisplayDevice extends AbstractSubscribable implements DisplayDevice { + + private final AWTGLCanvas canvas; + private final LwjglGraphicsManager graphics; + + public LwjglPortletDisplayDevice(AWTGLCanvas canvas, LwjglGraphicsManager graphics) { + this.canvas = canvas; + this.graphics = graphics; + canvas.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + updateViewport(); + } + }); + } + + @Override + public boolean hasFocus() { + return canvas.hasFocus(); + } + + @Override + public boolean isCloseRequested() { + return false; + } + + @Override + public void setFullscreen(boolean state) { + } + + @Override + public boolean isFullscreen() { + return false; + } + + @Override + public void setDisplayModeSetting(DisplayModeSetting displayModeSetting) { + } + + @Override + public DisplayModeSetting getDisplayModeSetting() { + return DisplayModeSetting.WINDOWED; + } + + @Override + public Resolution getResolution() { + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + int bitDepth = env.getDefaultScreenDevice().getDisplayMode().getBitDepth(); + int refreshRate = env.getDefaultScreenDevice().getDisplayMode().getRefreshRate(); + return new LwjglResolution(getWidth(), getHeight(), bitDepth, bitDepth, bitDepth, refreshRate); + } + + @Override + public List getResolutions() { + ArrayList resolutions = new ArrayList<>(); + resolutions.add(getResolution()); + return resolutions; + } + + @Override + public int getWidth() { + return canvas.getWidth(); + } + + @Override + public int getHeight() { + return canvas.getHeight(); + } + + @Override + public void setResolution(Resolution resolution) { + } + + @Override + public void processMessages() { + } + + @Override + public boolean isHeadless() { + return false; + } + + @Override + public void prepareToRender() { + } + + private void updateViewport() { + updateViewport(getWidth(), getHeight()); + } + + protected void updateViewport(int width, int height) { + graphics.asynchToDisplayThread(() -> { + GL11.glViewport(0, 0, width, height); + propertyChangeSupport.firePropertyChange(LwjglDisplayDevice.DISPLAY_RESOLUTION_CHANGE, 0, 1); + }); + } + + @Override + public void update() { + processMessages(); + canvas.swapBuffers(); + } + + @Override + public DisplayDeviceInfo getInfo() { + return graphics.getDisplayDeviceInfo(); + } +} diff --git a/facades/TeraEd/src/main/java/org/terasology/editor/ui/Viewport.java b/facades/TeraEd/src/main/java/org/terasology/editor/ui/Viewport.java index b41a0b86ee9..7eeafd5a205 100644 --- a/facades/TeraEd/src/main/java/org/terasology/editor/ui/Viewport.java +++ b/facades/TeraEd/src/main/java/org/terasology/editor/ui/Viewport.java @@ -15,23 +15,38 @@ */ package org.terasology.editor.ui; +import org.lwjgl.opengl.awt.AWTGLCanvas; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.awt.*; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Dimension; /** * TeraEd main class. */ @SuppressWarnings("serial") -public final class Viewport extends Canvas { +public final class Viewport extends JPanel { private static final Logger logger = LoggerFactory.getLogger(Viewport.class); + private JLabel startingLabel = new JLabel("Starting Terasology..."); public Viewport() { + setLayout(new BorderLayout()); setSize(1280, 720); setMinimumSize(new Dimension(640, 480)); setPreferredSize(new Dimension(1280, 720)); - setPreferredSize(new Dimension(1280, 720)); + setOpaque(false); + startingLabel.setHorizontalAlignment(SwingConstants.CENTER); + add(startingLabel, BorderLayout.CENTER); + } + + public void setTerasology(AWTGLCanvas canvas) { + remove(startingLabel); + add(canvas, BorderLayout.CENTER); + revalidate(); } } From f8f30158a9dcb9078386de3efce54dda40bbcebe Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 6 Jan 2021 13:13:05 -0800 Subject: [PATCH 094/259] feat(JOML): migrate BaseFacet2D for BlockArea (#4364) Co-authored-by: Tobias Nett --- .../Zones/LayeredZoneRegionFunctionTest.java | 3 +- .../logic/spawner/AbstractSpawner.java | 3 +- .../terasology/world/generation/Border3D.java | 16 ++++++----- .../world/generation/WorldFacet2D.java | 6 ++-- .../world/generation/WorldFacet3D.java | 7 ++--- .../world/generation/facets/DensityFacet.java | 5 ++-- .../generation/facets/ElevationFacet.java | 3 +- .../facets/base/BaseBooleanFieldFacet2D.java | 20 ++++++------- .../facets/base/BaseBooleanFieldFacet3D.java | 5 ++-- .../generation/facets/base/BaseFacet2D.java | 17 ++++++----- .../facets/base/BaseFieldFacet2D.java | 20 ++++++------- .../facets/base/BaseObjectFacet2D.java | 18 +++++------- .../facets/base/BaseSparseFacet2D.java | 28 +++++++++---------- .../base/BaseStrictlySparseFieldFacet2D.java | 12 ++++---- .../facets/base/BooleanFieldFacet2D.java | 12 ++++---- .../generation/facets/base/FieldFacet2D.java | 10 +++---- .../generation/facets/base/ObjectFacet2D.java | 10 +++---- .../base/SparseBooleanFieldFacet3D.java | 6 ++-- .../generation/facets/base/SparseFacet3D.java | 3 +- .../facets/base/SparseFieldFacet3D.java | 5 ++-- .../facets/base/SparseObjectFacet3D.java | 3 +- .../base/VerticallySparseBooleanFacet3D.java | 3 +- .../zones/LayeredZoneRegionFunction.java | 2 +- 23 files changed, 108 insertions(+), 109 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java index 97cac9a6d8f..e0feb3f0717 100644 --- a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java @@ -17,6 +17,7 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; +import org.joml.Vector2ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.math.geom.BaseVector2i; @@ -66,7 +67,7 @@ public void setup() { ElevationFacet facet = new ElevationFacet(generatingRegion.getRegion(), generatingRegion.getBorderForFacet(ElevationFacet.class)); - for (BaseVector2i pos : facet.getRelativeRegion().contents()) { + for (Vector2ic pos : facet.getRelativeArea()) { facet.set(pos, 100); } diff --git a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java index 628ffedd654..661d4131c8a 100644 --- a/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java +++ b/engine/src/main/java/org/terasology/logic/spawner/AbstractSpawner.java @@ -20,7 +20,6 @@ import org.joml.Vector2ic; import org.joml.Vector3f; import org.joml.Vector3i; -import org.terasology.math.JomlUtil; import org.terasology.math.SpiralIterable; import org.terasology.math.TeraMath; import org.terasology.world.block.BlockRegion; @@ -121,7 +120,7 @@ private int getStartHeight(World world, Vector2i pos) { ElevationFacet elevationFacet = worldRegion.getFacet(ElevationFacet.class); if (elevationFacet != null) { - return (int) elevationFacet.getWorld(JomlUtil.from(pos)); + return (int) elevationFacet.getWorld(pos); } else { // We'll have to rely on the SurfaceHeightFacet or SpawnHeightFacet anyway, and those are purely 2D so the height doesn't matter. return 0; diff --git a/engine/src/main/java/org/terasology/world/generation/Border3D.java b/engine/src/main/java/org/terasology/world/generation/Border3D.java index 2e42169f4f4..62b818c21b2 100644 --- a/engine/src/main/java/org/terasology/world/generation/Border3D.java +++ b/engine/src/main/java/org/terasology/world/generation/Border3D.java @@ -17,7 +17,9 @@ import com.google.common.base.Preconditions; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.math.geom.Rect2i; +import org.terasology.world.block.BlockArea; import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; @@ -70,19 +72,19 @@ public int getSides() { * @param region The original region to be used. * @return The 2D representation with the additional space added to it. */ - public Rect2i expandTo2D(BlockRegion region) { - return Rect2i.createFromMinAndMax(region.minX() - getSides(), region.minZ() - getSides(), + public BlockArea expandTo2D(BlockRegionc region) { + return new BlockArea(region.minX() - getSides(), region.minZ() - getSides(), region.maxX() + getSides(), region.maxZ() + getSides()); } /** - * Same as {@code {@link #expandTo2D(BlockRegion)}} but with a Vector3i instead of a Region3i. + * Same as {@code {@link #expandTo2D(BlockRegionc)}} but with a Vector3i instead of a Region3i. * @param size The size used. * @return The 2D representation with the additional space added to it with the additional space added to it in the 3 dimensions. */ //TODO: offer a variant that takes three integers to potentially avoid allocation of superfluous vectors - public Rect2i expandTo2D(Vector3i size) { - return Rect2i.createFromMinAndMax(-getSides(), -getSides(), size.x + getSides() - 1, size.z + getSides() - 1); + public BlockArea expandTo2D(Vector3ic size) { + return new BlockArea(-getSides(), -getSides(), size.x() + getSides() - 1, size.z() + getSides() - 1); } /** @@ -101,9 +103,9 @@ public BlockRegion expandTo3D(BlockRegionc region) { * @return The 3D world representation with the additional space added to it in the 3 dimensions. */ //TODO: offer a variant that takes three integers to potentially avoid allocation of superfluous vectors - public BlockRegion expandTo3D(Vector3i size) { + public BlockRegion expandTo3D(Vector3ic size) { return new BlockRegion(-sides, -bottom, -sides, - size.x + sides - 1, size.y + top - 1, size.z + sides - 1); + size.x() + sides - 1, size.y() + top - 1, size.z() + sides - 1); } /** diff --git a/engine/src/main/java/org/terasology/world/generation/WorldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/WorldFacet2D.java index ecd79ba7bb8..6f27d6cfeef 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldFacet2D.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation; -import org.terasology.math.geom.Rect2i; +import org.terasology.world.block.BlockAreac; /** */ @@ -24,10 +24,10 @@ public interface WorldFacet2D extends WorldFacet { /** * @return The region of the world covered by this facet */ - Rect2i getWorldRegion(); + BlockAreac getWorldArea(); /** * @return The region covered by this facet, relative to the target region */ - Rect2i getRelativeRegion(); + BlockAreac getRelativeArea(); } diff --git a/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java index 503f2e24f92..d4aec92f6aa 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldFacet3D.java @@ -15,8 +15,7 @@ */ package org.terasology.world.generation; -import org.terasology.math.Region3i; -import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; /** */ @@ -25,10 +24,10 @@ public interface WorldFacet3D extends WorldFacet { /** * @return The region of the world covered by this facet */ - BlockRegion getWorldRegion(); + BlockRegionc getWorldRegion(); /** * @return The region covered by this facet, relative to the target region */ - BlockRegion getRelativeRegion(); + BlockRegionc getRelativeRegion(); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java index 1cebea62245..a1c2985cf07 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/DensityFacet.java @@ -15,8 +15,7 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; -import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet3D; @@ -24,7 +23,7 @@ */ public class DensityFacet extends BaseFieldFacet3D { - public DensityFacet(BlockRegion targetRegion, Border3D border) { + public DensityFacet(BlockRegionc targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java index 62fca43a7c8..fae752b8077 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java @@ -5,6 +5,7 @@ import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; @@ -17,7 +18,7 @@ */ public class ElevationFacet extends BaseFieldFacet2D { - public ElevationFacet(BlockRegion targetRegion, Border3D border) { + public ElevationFacet(BlockRegionc targetRegion, Border3D border) { super(targetRegion, border); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java index e1b557c64e2..f57a2a86e9a 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java @@ -16,6 +16,7 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; +import org.joml.Vector2ic; import org.terasology.math.geom.Vector2i; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; @@ -31,8 +32,7 @@ public abstract class BaseBooleanFieldFacet2D extends BaseFacet2D implements Boo public BaseBooleanFieldFacet2D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); - Vector2i size = getRelativeRegion().size(); - data = new boolean[size.x * size.y]; + data = new boolean[getRelativeArea().area()]; } @Override @@ -41,8 +41,8 @@ public boolean get(int x, int y) { } @Override - public boolean get(Vector2i pos) { - return get(pos.x, pos.y); + public boolean get(Vector2ic pos) { + return get(pos.x(), pos.y()); } @Override @@ -51,8 +51,8 @@ public boolean getWorld(int x, int y) { } @Override - public boolean getWorld(Vector2i pos) { - return getWorld(pos.x, pos.y); + public boolean getWorld(Vector2ic pos) { + return getWorld(pos.x(), pos.y()); } /** @@ -70,8 +70,8 @@ public void set(int x, int y, boolean value) { } @Override - public void set(Vector2i pos, boolean value) { - set(pos.x, pos.y, value); + public void set(Vector2ic pos, boolean value) { + set(pos.x(), pos.y(), value); } @Override @@ -80,8 +80,8 @@ public void setWorld(int x, int y, boolean value) { } @Override - public void setWorld(Vector2i pos, boolean value) { - setWorld(pos.x, pos.y, value); + public void setWorld(Vector2ic pos, boolean value) { + setWorld(pos.x(), pos.y(), value); } /** diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java index e116c3cdd87..b37696c4d4f 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet3D.java @@ -29,8 +29,8 @@ public abstract class BaseBooleanFieldFacet3D extends BaseFacet3D implements Boo public BaseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border) { super(targetRegion, border); - Vector3i size = getRelativeRegion().getSize(new Vector3i()); - data = new boolean[size.x * size.y * size.z]; + data = + new boolean[getRelativeRegion().volume()]; } @Override @@ -81,5 +81,4 @@ public void set(boolean[] newData) { Preconditions.checkArgument(newData.length == data.length); System.arraycopy(newData, 0, data, 0, newData.length); } - } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java index 9c6c83a3276..ade1f74c402 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java @@ -18,7 +18,10 @@ import org.joml.Vector3i; import org.terasology.math.geom.Rect2i; import org.terasology.math.Region3i; +import org.terasology.world.block.BlockArea; +import org.terasology.world.block.BlockAreac; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet2D; @@ -26,21 +29,21 @@ */ public class BaseFacet2D implements WorldFacet2D { - private Rect2i worldRegion; - private Rect2i relativeRegion; + private BlockArea worldRegion; + private BlockArea relativeRegion; - public BaseFacet2D(BlockRegion targetRegion, Border3D border) { + public BaseFacet2D(BlockRegionc targetRegion, Border3D border) { worldRegion = border.expandTo2D(targetRegion); relativeRegion = border.expandTo2D(targetRegion.getSize(new Vector3i())); } @Override - public final Rect2i getWorldRegion() { + public final BlockAreac getWorldArea() { return worldRegion; } @Override - public final Rect2i getRelativeRegion() { + public final BlockAreac getRelativeArea() { return relativeRegion; } @@ -48,13 +51,13 @@ protected final int getRelativeIndex(int x, int z) { if (!relativeRegion.contains(x, z)) { throw new IllegalArgumentException(String.format("Out of bounds: (%d, %d) for region %s", x, z, relativeRegion.toString())); } - return x - relativeRegion.minX() + relativeRegion.sizeX() * (z - relativeRegion.minY()); + return x - relativeRegion.minX() + relativeRegion.getSizeX() * (z - relativeRegion.minY()); } protected final int getWorldIndex(int x, int z) { if (!worldRegion.contains(x, z)) { throw new IllegalArgumentException(String.format("Out of bounds: (%d, %d) for region %s", x, z, worldRegion.toString())); } - return x - worldRegion.minX() + worldRegion.sizeX() * (z - worldRegion.minY()); + return x - worldRegion.minX() + worldRegion.getSizeX() * (z - worldRegion.minY()); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java index d98a691012a..4b608894866 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFieldFacet2D.java @@ -16,11 +16,8 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; - -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Vector2i; -import org.terasology.world.block.BlockRegion; +import org.joml.Vector2ic; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; /** @@ -29,10 +26,9 @@ public abstract class BaseFieldFacet2D extends BaseFacet2D implements FieldFacet private float[] data; - public BaseFieldFacet2D(BlockRegion targetRegion, Border3D border) { + public BaseFieldFacet2D(BlockRegionc targetRegion, Border3D border) { super(targetRegion, border); - Vector2i size = getRelativeRegion().size(); - this.data = new float[size.x * size.y]; + this.data = new float[getRelativeArea().area()]; } @Override @@ -41,7 +37,7 @@ public float get(int x, int y) { } @Override - public float get(BaseVector2i pos) { + public float get(Vector2ic pos) { return get(pos.x(), pos.y()); } @@ -51,7 +47,7 @@ public float getWorld(int x, int y) { } @Override - public float getWorld(BaseVector2i pos) { + public float getWorld(Vector2ic pos) { return getWorld(pos.x(), pos.y()); } @@ -65,7 +61,7 @@ public void set(int x, int y, float value) { } @Override - public void set(BaseVector2i pos, float value) { + public void set(Vector2ic pos, float value) { set(pos.x(), pos.y(), value); } @@ -75,7 +71,7 @@ public void setWorld(int x, int y, float value) { } @Override - public void setWorld(BaseVector2i pos, float value) { + public void setWorld(Vector2ic pos, float value) { setWorld(pos.x(), pos.y(), value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java index b9a899fb9b3..65c09cb75cf 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseObjectFacet2D.java @@ -16,10 +16,7 @@ package org.terasology.world.generation.facets.base; import com.google.common.base.Preconditions; - -import org.terasology.math.Region3i; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Vector2i; +import org.joml.Vector2ic; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; @@ -33,8 +30,7 @@ public abstract class BaseObjectFacet2D extends BaseFacet2D implements Object public BaseObjectFacet2D(BlockRegion targetRegion, Border3D border, Class objectType) { super(targetRegion, border); - Vector2i size = getRelativeRegion().size(); - this.data = (T[]) Array.newInstance(objectType, size.x * size.y); + this.data = (T[]) Array.newInstance(objectType, getRelativeArea().area()); } @Override @@ -43,7 +39,7 @@ public T get(int x, int y) { } @Override - public T get(BaseVector2i pos) { + public T get(Vector2ic pos) { return get(pos.x(), pos.y()); } @@ -53,7 +49,7 @@ public T getWorld(int x, int y) { } @Override - public T getWorld(BaseVector2i pos) { + public T getWorld(Vector2ic pos) { return getWorld(pos.x(), pos.y()); } @@ -67,8 +63,8 @@ public void set(int x, int y, T value) { } @Override - public void set(BaseVector2i pos, T value) { - set(pos.getX(), pos.getY(), value); + public void set(Vector2ic pos, T value) { + set(pos.x(), pos.y(), value); } @Override @@ -77,7 +73,7 @@ public void setWorld(int x, int y, T value) { } @Override - public void setWorld(BaseVector2i pos, T value) { + public void setWorld(Vector2ic pos, T value) { setWorld(pos.x(), pos.y(), value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java index 380196ff0b1..a32f4acf953 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseSparseFacet2D.java @@ -18,7 +18,7 @@ import org.joml.Vector2i; import org.joml.Vector2ic; import org.joml.Vector3i; -import org.terasology.math.geom.Rect2i; +import org.terasology.world.block.BlockAreac; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet2D; @@ -27,33 +27,33 @@ * A base class for sparse (map-based) 2D facets. */ public abstract class BaseSparseFacet2D implements WorldFacet2D { - private Rect2i worldRegion; - private Rect2i relativeRegion; + private BlockAreac worldArea; + private BlockAreac relativeArea; public BaseSparseFacet2D(BlockRegion targetRegion, Border3D border) { - worldRegion = border.expandTo2D(targetRegion); - relativeRegion = border.expandTo2D(targetRegion.getSize(new Vector3i())); + worldArea = border.expandTo2D(targetRegion); + relativeArea = border.expandTo2D(targetRegion.getSize(new Vector3i())); } @Override - public Rect2i getWorldRegion() { - return worldRegion; + public BlockAreac getWorldArea() { + return worldArea; } @Override - public Rect2i getRelativeRegion() { - return relativeRegion; + public BlockAreac getRelativeArea() { + return relativeArea; } protected Vector2ic worldToRelative(int x, int y) { - return new Vector2i(x - getWorldRegion().minX() + getRelativeRegion().minX(), - y - getWorldRegion().minY() + getRelativeRegion().minY()); + return new Vector2i(x - getWorldArea().minX() + getRelativeArea().minX(), + y - getWorldArea().minY() + getRelativeArea().minY()); } - protected void validateCoord(int x, int y, Rect2i region) { - if(!region.contains(x, y)) { + protected void validateCoord(int x, int y, BlockAreac area) { + if(!area.contains(x, y)) { String text = "Out of bounds: (%d, %d) for region %s"; - String msg = String.format(text, x, y, region.toString()); + String msg = String.format(text, x, y, area.toString()); throw new IllegalArgumentException(msg); } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java index 1489c0dfae7..e3e5482a054 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseStrictlySparseFieldFacet2D.java @@ -38,13 +38,13 @@ public Optional get(int x, int y) { } public Optional get(Vector2ic pos) { - validateCoord(pos.x(), pos.y(), getRelativeRegion()); + validateCoord(pos.x(), pos.y(), getRelativeArea()); return Optional.ofNullable(data.getOrDefault(pos, null)); } public Optional getWorld(int x, int y) { - validateCoord(x, y, getWorldRegion()); + validateCoord(x, y, getWorldArea()); return Optional.ofNullable(data.getOrDefault(worldToRelative(x, y), null)); } @@ -58,13 +58,13 @@ public void set(int x, int y, float value) { } public void set(Vector2ic pos, float value) { - validateCoord(pos.x(), pos.y(), getRelativeRegion()); + validateCoord(pos.x(), pos.y(), getRelativeArea()); data.put(pos, value); } public void setWorld(int x, int y, float value) { - validateCoord(x, y, getWorldRegion()); + validateCoord(x, y, getWorldArea()); data.put(worldToRelative(x, y), value); } @@ -78,13 +78,13 @@ public void unset(int x, int y) { } public void unset(Vector2ic pos) { - validateCoord(pos.x(), pos.y(), getRelativeRegion()); + validateCoord(pos.x(), pos.y(), getRelativeArea()); data.remove(pos); } public void unsetWorld(int x, int y) { - validateCoord(x, y, getWorldRegion()); + validateCoord(x, y, getWorldArea()); data.remove(worldToRelative(x, y)); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet2D.java index 611ecee780f..5aed8c69b62 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BooleanFieldFacet2D.java @@ -15,12 +15,12 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.Vector2i; +import org.joml.Vector2ic; import org.terasology.world.generation.WorldFacet2D; /** * A {@link WorldFacet2D}-based facet that provides boolean values - * for rectangular area (see {@link #getWorldRegion()} and {@link #getRelativeRegion()}). + * for rectangular area (see {@link #getWorldArea()} and {@link #getRelativeArea()}. * Its entries are accessible through both relative and world coordinates (in blocks). *

* All methods throw {@link IllegalArgumentException} if coordinates are not inside the respective region. @@ -29,17 +29,17 @@ public interface BooleanFieldFacet2D extends WorldFacet2D { boolean get(int x, int y); - boolean get(Vector2i pos); + boolean get(Vector2ic pos); boolean getWorld(int x, int y); - boolean getWorld(Vector2i pos); + boolean getWorld(Vector2ic pos); void set(int x, int y, boolean value); - void set(Vector2i pos, boolean value); + void set(Vector2ic pos, boolean value); void setWorld(int x, int y, boolean value); - void setWorld(Vector2i pos, boolean value); + void setWorld(Vector2ic pos, boolean value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet2D.java index 12a66ab4e0a..eb3563a40c3 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/FieldFacet2D.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.BaseVector2i; +import org.joml.Vector2ic; import org.terasology.world.generation.WorldFacet2D; /** @@ -24,17 +24,17 @@ public interface FieldFacet2D extends WorldFacet2D { float get(int x, int y); - float get(BaseVector2i pos); + float get(Vector2ic pos); float getWorld(int x, int y); - float getWorld(BaseVector2i pos); + float getWorld(Vector2ic pos); void set(int x, int y, float value); - void set(BaseVector2i pos, float value); + void set(Vector2ic pos, float value); void setWorld(int x, int y, float value); - void setWorld(BaseVector2i pos, float value); + void setWorld(Vector2ic pos, float value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet2D.java index 58e555197de..e3e1ff49702 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/ObjectFacet2D.java @@ -15,7 +15,7 @@ */ package org.terasology.world.generation.facets.base; -import org.terasology.math.geom.BaseVector2i; +import org.joml.Vector2ic; import org.terasology.world.generation.WorldFacet2D; /** @@ -24,17 +24,17 @@ public interface ObjectFacet2D extends WorldFacet2D { T get(int x, int y); - T get(BaseVector2i pos); + T get(Vector2ic pos); T getWorld(int x, int y); - T getWorld(BaseVector2i pos); + T getWorld(Vector2ic pos); void set(int x, int y, T value); - void set(BaseVector2i pos, T value); + void set(Vector2ic pos, T value); void setWorld(int x, int y, T value); - void setWorld(BaseVector2i pos, T value); + void setWorld(Vector2ic pos, T value); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java index 39a349c8593..71777472154 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseBooleanFieldFacet3D.java @@ -19,7 +19,7 @@ import com.google.common.collect.Maps; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -35,11 +35,11 @@ public abstract class SparseBooleanFieldFacet3D extends SparseFacet3D implements private final boolean defValue; - public SparseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border) { + public SparseBooleanFieldFacet3D(BlockRegionc targetRegion, Border3D border) { this(targetRegion, border, false); } - public SparseBooleanFieldFacet3D(BlockRegion targetRegion, Border3D border, boolean defValue) { + public SparseBooleanFieldFacet3D(BlockRegionc targetRegion, Border3D border, boolean defValue) { super(targetRegion, border); this.defValue = defValue; } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java index 4fa7754872b..7f560afca1d 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFacet3D.java @@ -18,6 +18,7 @@ import org.joml.Vector3i; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; @@ -29,7 +30,7 @@ public abstract class SparseFacet3D implements WorldFacet3D { private BlockRegion worldRegion; private BlockRegion relativeRegion; - public SparseFacet3D(BlockRegion targetRegion, Border3D border) { + public SparseFacet3D(BlockRegionc targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java index d3321b4c6fc..ef1f67e2216 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseFieldFacet3D.java @@ -20,6 +20,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -38,11 +39,11 @@ public abstract class SparseFieldFacet3D extends SparseFacet3D implements FieldF private final float defValue; - public SparseFieldFacet3D(BlockRegion targetRegion, Border3D border) { + public SparseFieldFacet3D(BlockRegionc targetRegion, Border3D border) { this(targetRegion, border, 0); } - public SparseFieldFacet3D(BlockRegion targetRegion, Border3D border, float defValue) { + public SparseFieldFacet3D(BlockRegionc targetRegion, Border3D border, float defValue) { super(targetRegion, border); this.defValue = defValue; } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java index 3e00ceecb1d..e174d714cdd 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java @@ -20,6 +20,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import java.util.Collections; @@ -39,7 +40,7 @@ public abstract class SparseObjectFacet3D extends SparseFacet3D implements Ob * @param targetRegion * @param border */ - public SparseObjectFacet3D(BlockRegion targetRegion, Border3D border) { + public SparseObjectFacet3D(BlockRegionc targetRegion, Border3D border) { super(targetRegion, border); } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java index 6524ccd7773..c987c9c9474 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/VerticallySparseBooleanFacet3D.java @@ -6,6 +6,7 @@ import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet3D; @@ -22,7 +23,7 @@ public class VerticallySparseBooleanFacet3D implements WorldFacet3D { private BlockRegion relativeRegion; private Set[] data; - public VerticallySparseBooleanFacet3D(BlockRegion targetRegion, Border3D border) { + public VerticallySparseBooleanFacet3D(BlockRegionc targetRegion, Border3D border) { worldRegion = border.expandTo3D(targetRegion); relativeRegion = border.expandTo3D(targetRegion.getSize(new Vector3i())); data = new Set[worldRegion.getSizeX() * worldRegion.getSizeZ()]; diff --git a/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java b/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java index 0f860ad7a2d..9fc1553833b 100644 --- a/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java +++ b/engine/src/main/java/org/terasology/world/zones/LayeredZoneRegionFunction.java @@ -15,7 +15,7 @@ */ package org.terasology.world.zones; -import org.terasology.math.geom.Vector2i; +import org.joml.Vector2i; import org.terasology.module.sandbox.API; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.generation.Region; From db595762165161511b6517204c1595101e1d0cf4 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 7 Jan 2021 20:41:04 -0800 Subject: [PATCH 095/259] feat(JOML): migrate WorldGenerator#getSpawnPosition (#4380) * feat(JOML): migrate WorldGenerator#getSpawnPosition * update PlayerSystem --- .../java/org/terasology/logic/players/PlayerSystem.java | 6 +++--- .../org/terasology/world/generator/WorldGenerator.java | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java index a1899685c0f..e8271b7e8dc 100644 --- a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java @@ -153,7 +153,7 @@ public void onConnect(ConnectedEvent connected, EntityRef entity) { clientsPreparingToSpawn.add(new SpawningClientInfo(entity, storedLocation, playerStore)); } } else { - Vector3f spawnPosition = JomlUtil.from(worldGenerator.getSpawnPosition(entity)); + Vector3fc spawnPosition = worldGenerator.getSpawnPosition(entity); loc.setWorldPosition(spawnPosition); entity.saveComponent(loc); @@ -222,11 +222,11 @@ public void setSpawnLocationOnRespawnRequest(RespawnRequestEvent event, EntityRe EntityRef character = clientComponent.character; EntityRef clientInfo = clientComponent.clientInfo; - Vector3f spawnPosition; + Vector3fc spawnPosition; if (clientInfo.hasComponent(StaticSpawnLocationComponent.class)) { spawnPosition = clientInfo.getComponent(StaticSpawnLocationComponent.class).position; } else { - spawnPosition = JomlUtil.from(worldGenerator.getSpawnPosition(entity)); + spawnPosition = worldGenerator.getSpawnPosition(entity); } LocationComponent loc = character.getComponent(LocationComponent.class); loc.setWorldPosition(spawnPosition); diff --git a/engine/src/main/java/org/terasology/world/generator/WorldGenerator.java b/engine/src/main/java/org/terasology/world/generator/WorldGenerator.java index acb343eabc6..a022ce77065 100644 --- a/engine/src/main/java/org/terasology/world/generator/WorldGenerator.java +++ b/engine/src/main/java/org/terasology/world/generator/WorldGenerator.java @@ -16,11 +16,10 @@ package org.terasology.world.generator; +import org.joml.Vector3fc; import org.terasology.engine.SimpleUri; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.spawner.FixedSpawner; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.world.chunks.CoreChunk; import org.terasology.world.generation.EntityBuffer; import org.terasology.world.generation.World; @@ -89,7 +88,7 @@ default Zone getNamedZone(String name) { * @param entity the entity related to spawning, if needed (or not). Can be ignored. * @return the chosen position */ - default Vector3f getSpawnPosition(EntityRef entity) { - return JomlUtil.from(new FixedSpawner(0, 0).getSpawnPosition(getWorld(), entity)); + default Vector3fc getSpawnPosition(EntityRef entity) { + return new FixedSpawner(0, 0).getSpawnPosition(getWorld(), entity); } } From dff2d73c097a0ecd172cce4a8fd94e12ca1be440 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 9 Jan 2021 04:26:44 -0800 Subject: [PATCH 096/259] feat(JOML): migrate CharacterMoveInputEvent (#4376) --- .../org/terasology/logic/ai/HierarchicalAISystem.java | 3 ++- .../java/org/terasology/logic/ai/SimpleAISystem.java | 3 ++- .../logic/characters/CharacterMoveInputEvent.java | 11 ++++++----- .../logic/characters/KinematicCharacterMover.java | 2 +- .../terasology/logic/players/LocalPlayerSystem.java | 5 ++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java index f2003e52a01..8ec92d41805 100644 --- a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java +++ b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java @@ -28,6 +28,7 @@ import org.terasology.logic.characters.events.HorizontalCollisionEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; @@ -210,7 +211,7 @@ private void loop(EntityRef entity, LocationComponent location, drive.set(targetDirection); float yaw = (float) Math.atan2(targetDirection.x, targetDirection.z); - entity.send(new CharacterMoveInputEvent(0, 0, yaw, drive, false, false, time.getGameDeltaInMs())); + entity.send(new CharacterMoveInputEvent(0, 0, yaw, JomlUtil.from(drive), false, false, time.getGameDeltaInMs())); entity.saveComponent(location); // System.out.print("\Destination set: " + targetDirection.x + ":" +targetDirection.z + "\n"); // System.out.print("\nI am: " + worldPos.x + ":" + worldPos.z + "\n"); diff --git a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java index 52c9a107d09..a0a07043e5c 100644 --- a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java +++ b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java @@ -28,6 +28,7 @@ import org.terasology.logic.characters.events.HorizontalCollisionEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; @@ -92,7 +93,7 @@ public void update(float delta) { location.getLocalRotation().set(new Vector3f(0, 1, 0), yaw); entity.saveComponent(location); } - entity.send(new CharacterMoveInputEvent(0, 0, 0, drive, false, false, time.getGameDeltaInMs())); + entity.send(new CharacterMoveInputEvent(0, 0, 0, JomlUtil.from(drive), false, false, time.getGameDeltaInMs())); } } diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterMoveInputEvent.java b/engine/src/main/java/org/terasology/logic/characters/CharacterMoveInputEvent.java index 8794a27f8cb..1ea5756d709 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterMoveInputEvent.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterMoveInputEvent.java @@ -16,7 +16,8 @@ package org.terasology.logic.characters; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; +import org.joml.Vector3fc; import org.terasology.network.NetworkEvent; import org.terasology.network.ServerEvent; @@ -38,11 +39,11 @@ protected CharacterMoveInputEvent() { } @Deprecated - public CharacterMoveInputEvent(int sequence, float pitch, float yaw, Vector3f movementDirection, boolean running, boolean jumpRequested, long delta) { + public CharacterMoveInputEvent(int sequence, float pitch, float yaw, Vector3fc movementDirection, boolean running, boolean jumpRequested, long delta) { this(sequence, pitch, yaw, movementDirection, running, false, jumpRequested, delta); } - public CharacterMoveInputEvent(int sequence, float pitch, float yaw, Vector3f movementDirection, boolean running, boolean crouching, boolean jumpRequested, long delta) { + public CharacterMoveInputEvent(int sequence, float pitch, float yaw, Vector3fc movementDirection, boolean running, boolean crouching, boolean jumpRequested, long delta) { this.delta = delta; this.pitch = pitch; this.yaw = yaw; @@ -80,8 +81,8 @@ public float getYaw() { return yaw; } - public Vector3f getMovementDirection() { - return new Vector3f(movementDirection); + public Vector3fc getMovementDirection() { + return movementDirection; } public boolean isRunning() { diff --git a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java index 7e21e515025..095e983fa9c 100644 --- a/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java +++ b/engine/src/main/java/org/terasology/logic/characters/KinematicCharacterMover.java @@ -586,7 +586,7 @@ private void updateRotation(CharacterMovementComponent movementComp, CharacterSt private void walk(final CharacterMovementComponent movementComp, final CharacterStateEvent state, CharacterMoveInputEvent input, EntityRef entity) { - Vector3f desiredVelocity = new Vector3f(JomlUtil.from(input.getMovementDirection())); + Vector3f desiredVelocity = new Vector3f(input.getMovementDirection()); float lengthSquared = desiredVelocity.lengthSquared(); diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java index e634fd945fb..e81c7ff4a15 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java @@ -64,7 +64,6 @@ import org.terasology.logic.players.event.OnPlayerSpawnedEvent; import org.terasology.math.AABB; import org.terasology.math.JomlUtil; -import org.terasology.math.TeraMath; import org.terasology.network.ClientComponent; import org.terasology.network.NetworkMode; import org.terasology.network.NetworkSystem; @@ -189,7 +188,7 @@ private void processInput(EntityRef entity, CharacterMovementComponent character } // For some reason, Quat4f.rotate is returning NaN for valid inputs. This prevents those NaNs from causing trouble down the line. if (relMove.isFinite()) { - entity.send(new CharacterMoveInputEvent(inputSequenceNumber++, lookPitch, lookYaw, JomlUtil.from(relMove), run, crouch, jump, time.getGameDeltaInMs())); + entity.send(new CharacterMoveInputEvent(inputSequenceNumber++, lookPitch, lookYaw, relMove, run, crouch, jump, time.getGameDeltaInMs())); } jump = false; } @@ -413,7 +412,7 @@ public void setAABBRenderer(BlockOverlayRenderer newAABBRender) { private void updateCamera(CharacterMovementComponent charMovementComp, Vector3f position, Quaternionf rotation) { playerCamera.getPosition().set(position); - playerCamera.setOrientation(JomlUtil.from(rotation)); + playerCamera.setOrientation(rotation); float stepDelta = charMovementComp.footstepDelta - lastStepDelta; if (stepDelta < 0) { From 8b5c4ae627343c19046bca51a25e2c6646c04ee3 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 9 Jan 2021 09:41:19 -0800 Subject: [PATCH 097/259] feat(JOML): migrate chunkview and tests cases (#4335) * chore(joml): replace ChunkMath and ChunkConstants with `Chunks` Co-authored-by: Tobias Nett --- .../org/terasology/world/ChunkViewTest.java | 39 ++--- .../java/org/terasology/world/ChunkView.java | 29 ++-- .../LocalChunkProvider.java | 2 +- .../RemoteChunkProvider.java | 2 +- .../world/internal/ChunkViewCore.java | 22 --- .../world/internal/ChunkViewCoreImpl.java | 133 ++++++++---------- .../world/propagation/AbstractChunkView.java | 5 +- 7 files changed, 101 insertions(+), 131 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/ChunkViewTest.java b/engine-tests/src/test/java/org/terasology/world/ChunkViewTest.java index 2589bdf22a2..4e2e48c808e 100644 --- a/engine-tests/src/test/java/org/terasology/world/ChunkViewTest.java +++ b/engine-tests/src/test/java/org/terasology/world/ChunkViewTest.java @@ -15,16 +15,17 @@ */ package org.terasology.world; +import org.joml.Vector3i; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.JomlUtil; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockUri; import org.terasology.world.block.family.SymmetricFamily; import org.terasology.world.block.internal.BlockManagerImpl; @@ -56,7 +57,7 @@ public void setup() throws IOException { blockManager = new BlockManagerImpl(new NullWorldAtlas(), assetManager); CoreRegistry.put(BlockManager.class, blockManager); airBlock = blockManager.getBlock(BlockManager.AIR_ID); - + extraDataManager = new ExtraBlockDataManager(); BlockFamilyDefinitionData solidData = new BlockFamilyDefinitionData(); @@ -73,7 +74,7 @@ public void testSimpleWorldView() { Chunk chunk = createChunk(0, 0, 0); chunk.setBlock(new Vector3i(0, 0, 0), solidBlock); - ChunkViewCore chunkView = new ChunkViewCoreImpl(new Chunk[]{chunk}, Region3i.createFromCenterExtents(Vector3i.zero(), Vector3i.zero()), new Vector3i(), airBlock); + ChunkViewCore chunkView = new ChunkViewCoreImpl(new Chunk[]{chunk}, new BlockRegion(0,0,0), new Vector3i(), airBlock); assertEquals(solidBlock, chunkView.getBlock(0, 0, 0)); } @@ -83,11 +84,11 @@ public void testOffsetWorldView() { chunk.setBlock(new Vector3i(0, 0, 0), solidBlock); Chunk[] chunks = new Chunk[]{createChunk(-1, 0, -1), createChunk(0, 0, -1), createChunk(1, 0, -1), - createChunk(-1, 0, 0), chunk, createChunk(1, 0, 0), - createChunk(-1, 0, 1), createChunk(0, 0, 1), createChunk(1, 0, 1)}; + createChunk(-1, 0, 0), chunk, createChunk(1, 0, 0), + createChunk(-1, 0, 1), createChunk(0, 0, 1), createChunk(1, 0, 1)}; ChunkViewCore chunkView = new ChunkViewCoreImpl(chunks, - Region3i.createFromCenterExtents(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)), new Vector3i(1, 0, 1), airBlock); + new BlockRegion(0, 0, 0).expand(1, 0, 1), new Vector3i(1, 0, 1), airBlock); assertEquals(solidBlock, chunkView.getBlock(0, 0, 0)); } @@ -101,7 +102,7 @@ public void testOffsetWorldViewBeforeMainChunk() { createChunk(-1, 0, 1), createChunk(0, 0, 1), createChunk(1, 0, 1)}; ChunkViewCore chunkView = new ChunkViewCoreImpl(chunks, - Region3i.createFromCenterExtents(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)), new Vector3i(1, 0, 1), airBlock); + new BlockRegion(0, 0, 0).expand(1, 0, 1), new Vector3i(1, 0, 1), airBlock); assertEquals(solidBlock, chunkView.getBlock(-1, 0, -1)); } @@ -111,11 +112,11 @@ public void testOffsetWorldViewAfterMainChunk() { chunk.setBlock(new Vector3i(0, 0, 0), solidBlock); Chunk[] chunks = new Chunk[]{createChunk(-1, 0, -1), createChunk(0, 0, -1), createChunk(1, 0, -1), - createChunk(-1, 0, 0), createChunk(0, 0, 0), createChunk(1, 0, 0), - createChunk(-1, 0, 1), createChunk(0, 0, 1), chunk}; + createChunk(-1, 0, 0), createChunk(0, 0, 0), createChunk(1, 0, 0), + createChunk(-1, 0, 1), createChunk(0, 0, 1), chunk}; ChunkViewCore chunkView = new ChunkViewCoreImpl(chunks, - Region3i.createFromCenterExtents(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1)), new Vector3i(1, 0, 1), airBlock); + new BlockRegion(0, 0, 0).expand(1, 0, 1), new Vector3i(1, 0, 1), airBlock); assertEquals(solidBlock, chunkView.getBlock(ChunkConstants.SIZE_X, 0, ChunkConstants.SIZE_Z)); } @@ -125,11 +126,11 @@ public void testOffsetChunksWorldView() { chunk.setBlock(new Vector3i(0, 0, 0), solidBlock); Chunk[] chunks = new Chunk[]{createChunk(0, 0, 0), createChunk(1, 0, 0), createChunk(2, 0, 0), - createChunk(0, 0, 1), chunk, createChunk(2, 0, 1), - createChunk(0, 0, 2), createChunk(1, 0, 2), createChunk(2, 0, 2)}; + createChunk(0, 0, 1), chunk, createChunk(2, 0, 1), + createChunk(0, 0, 2), createChunk(1, 0, 2), createChunk(2, 0, 2)}; ChunkViewCore chunkView = new ChunkViewCoreImpl(chunks, - Region3i.createFromCenterExtents(new Vector3i(1, 0, 1), new Vector3i(1, 0, 1)), new Vector3i(1, 0, 1), airBlock); + new BlockRegion(1, 0, 1).expand(1, 0, 1), new Vector3i(1, 0, 1), airBlock); assertEquals(solidBlock, chunkView.getBlock(0, 0, 0)); } @@ -139,15 +140,15 @@ public void testLocalToWorld() { chunk.setBlock(new Vector3i(0, 0, 0), solidBlock); Chunk[] chunks = new Chunk[]{createChunk(0, 0, 0), createChunk(1, 0, 0), createChunk(2, 0, 0), - createChunk(0, 0, 1), chunk, createChunk(2, 0, 1), - createChunk(0, 0, 2), createChunk(1, 0, 2), createChunk(2, 0, 2)}; + createChunk(0, 0, 1), chunk, createChunk(2, 0, 1), + createChunk(0, 0, 2), createChunk(1, 0, 2), createChunk(2, 0, 2)}; ChunkViewCoreImpl chunkView = new ChunkViewCoreImpl(chunks, - Region3i.createFromCenterExtents(new Vector3i(1, 0, 1), new Vector3i(1, 0, 1)), new Vector3i(1, 1, 1), airBlock); - assertEquals(new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z), chunkView.toWorldPos(Vector3i.zero())); + new BlockRegion(1, 0, 1).expand(1, 0, 1), new Vector3i(1, 1, 1), airBlock); + assertEquals(new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z), chunkView.toWorldPos(new Vector3i())); } private Chunk createChunk(int x, int y, int z) { - return new ChunkImpl(new Vector3i(x, y, z), blockManager, extraDataManager); + return new ChunkImpl(JomlUtil.from(new Vector3i(x, y, z)), blockManager, extraDataManager); } } diff --git a/engine/src/main/java/org/terasology/world/ChunkView.java b/engine/src/main/java/org/terasology/world/ChunkView.java index 48a52655149..57d5b95760a 100644 --- a/engine/src/main/java/org/terasology/world/ChunkView.java +++ b/engine/src/main/java/org/terasology/world/ChunkView.java @@ -15,9 +15,10 @@ */ package org.terasology.world; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegionc; /** * A chunk view is a way of accessing multiple chunks for modification in a performant manner. @@ -40,7 +41,7 @@ public interface ChunkView { * @param pos * @return The block at the given position. If this is outside of the view then the air block is returned */ - Block getBlock(Vector3i pos); + Block getBlock(Vector3ic pos); /** * @param x @@ -100,7 +101,7 @@ public interface ChunkView { * @param pos * @param type */ - void setBlock(Vector3i pos, Block type); + void setBlock(Vector3ic pos, Block type); /** * Sets the block at the given coordinates, if it is within the view. @@ -122,7 +123,7 @@ public interface ChunkView { * @return The (index)th extra-data value at the given position */ int getExtraData(int index, int x, int y, int z); - + /** * Gets one of the per-block custom data values at the given position. Returns 0 outside the view. * @@ -130,8 +131,8 @@ public interface ChunkView { * @param pos * @return The (index)th extra-data value at the given position */ - int getExtraData(int index, Vector3i pos); - + int getExtraData(int index, Vector3ic pos); + /** * Sets one of the per-block custom data values at the given position, if it is within the view. * @@ -142,7 +143,7 @@ public interface ChunkView { * @param value */ void setExtraData(int index, int x, int y, int z, int value); - + /** * Sets one of the per-block custom data values at the given position, if it is within the view. * @@ -150,7 +151,7 @@ public interface ChunkView { * @param pos * @param value */ - void setExtraData(int index, Vector3i pos, int value); + void setExtraData(int index, Vector3ic pos, int value); /** * Converts a coordinate from view-space to world space. @@ -158,17 +159,17 @@ public interface ChunkView { * @param localPos * @return The equivalent world-space coordinate for the given view coord. */ - Vector3i toWorldPos(Vector3i localPos); + Vector3i toWorldPos(Vector3ic localPos); /** * @return The region of the world which this view is over */ - Region3i getWorldRegion(); + BlockRegionc getWorldRegion(); /** * @return A Region3i denoting the chunks covered by this view */ - Region3i getChunkRegion(); + BlockRegionc getChunkRegion(); /** * Sets the chunks containing or adjacent to blockPos, which are contained in the chunk view, to dirty. This causes @@ -176,7 +177,7 @@ public interface ChunkView { * * @param blockPos */ - void setDirtyAround(Vector3i blockPos); + void setDirtyAround(Vector3ic blockPos); /** * Sets ths chunks contained or adjacent to blockRegion, which are contained in the chunk view, to dirty. This causes @@ -184,7 +185,7 @@ public interface ChunkView { * * @param blockRegion */ - void setDirtyAround(Region3i blockRegion); + void setDirtyAround(BlockRegionc blockRegion); /** diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 7ca09258282..e5dd1a8f9c6 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -180,7 +180,7 @@ private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); chunks[index] = chunk; } - return new ChunkViewCoreImpl(chunks, region, offset, blockManager.getBlock(BlockManager.AIR_ID)); + return new ChunkViewCoreImpl(chunks, JomlUtil.from(region), JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); } @Override diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 422e403b7c6..9f9c5aa707e 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -227,7 +227,7 @@ private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); chunks[index] = chunk; } - return new ChunkViewCoreImpl(chunks, region, offset, blockManager.getBlock(BlockManager.AIR_ID)); + return new ChunkViewCoreImpl(chunks, JomlUtil.from(region), JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); } @Override diff --git a/engine/src/main/java/org/terasology/world/internal/ChunkViewCore.java b/engine/src/main/java/org/terasology/world/internal/ChunkViewCore.java index 6c2ad427dbf..38e9cc2d645 100644 --- a/engine/src/main/java/org/terasology/world/internal/ChunkViewCore.java +++ b/engine/src/main/java/org/terasology/world/internal/ChunkViewCore.java @@ -22,17 +22,6 @@ public interface ChunkViewCore extends ChunkView { - /** - * Sets the light level at the given position. the value is usually bounded by {@link org.terasology.world.chunks.ChunkConstants#MAX_LIGHT} - * - * @param pos The position relative to the corner of the chunk - * @param light set the light value of a block. - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setLight(Vector3ic, byte)}. - */ - @Deprecated - void setLight(Vector3i pos, byte light); - /** * Sets the light level at the given position. the value is usually bounded by {@link org.terasology.world.chunks.ChunkConstants#MAX_LIGHT} * @@ -51,17 +40,6 @@ public interface ChunkViewCore extends ChunkView { */ void setLight(int blockX, int blockY, int blockZ, byte light); - /** - * Sets the sunlight level at the given position. the value is usually bounded by {@link org.terasology.world.chunks.ChunkConstants#MAX_SUNLIGHT} - * - * @param pos The position relative to the corner of the chunk - * @param light set the sunlight light value of a block. - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setSunlight(Vector3ic, byte)}. - */ - @Deprecated - void setSunlight(Vector3i pos, byte light); - /** * Sets the sunlight level at the given position. the value is usually bounded by {@link org.terasology.world.chunks.ChunkConstants#MAX_SUNLIGHT} diff --git a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java index 3a100cf03ef..2065d04e7d0 100644 --- a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java @@ -16,16 +16,17 @@ package org.terasology.world.internal; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.math.ChunkMath; -import org.terasology.math.Region3i; +import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.chunks.Chunk; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; /** */ @@ -33,9 +34,9 @@ public class ChunkViewCoreImpl implements ChunkViewCore { private static final Logger logger = LoggerFactory.getLogger(ChunkViewCoreImpl.class); - private Vector3i offset; - private Region3i chunkRegion; - private Region3i blockRegion; + private Vector3i offset = new Vector3i(); + private BlockRegion chunkRegion = new BlockRegion(BlockRegion.INVALID); + private BlockRegion blockRegion = new BlockRegion(BlockRegion.INVALID); private Chunk[] chunks; private Vector3i chunkPower; @@ -43,21 +44,21 @@ public class ChunkViewCoreImpl implements ChunkViewCore { private Block defaultBlock; - public ChunkViewCoreImpl(Chunk[] chunks, Region3i chunkRegion, Vector3i offset, Block defaultBlock) { - this.chunkRegion = chunkRegion; + public ChunkViewCoreImpl(Chunk[] chunks, BlockRegionc chunkRegion, Vector3ic offset, Block defaultBlock) { + this.chunkRegion.set(chunkRegion); this.chunks = chunks; - this.offset = offset; - setChunkSize(new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z)); + this.offset.set(offset); + setChunkSize(new Vector3i(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z)); this.defaultBlock = defaultBlock; } @Override - public Region3i getWorldRegion() { + public BlockRegionc getWorldRegion() { return blockRegion; } @Override - public Region3i getChunkRegion() { + public BlockRegionc getChunkRegion() { return chunkRegion; } @@ -67,22 +68,22 @@ public Block getBlock(float x, float y, float z) { } @Override - public Block getBlock(Vector3i pos) { - return getBlock(pos.x, pos.y, pos.z); + public Block getBlock(Vector3ic pos) { + return getBlock(pos.x(), pos.y(), pos.z()); } // TODO: Review @Override public Block getBlock(int blockX, int blockY, int blockZ) { - if (!blockRegion.encompasses(blockX, blockY, blockZ)) { + if (!blockRegion.contains(blockX, blockY, blockZ)) { return defaultBlock; } int chunkIndex = relChunkIndex(blockX, blockY, blockZ); return chunks[chunkIndex].getBlock( - ChunkMath.calcRelativeBlockPos(blockX, chunkFilterSize.x), - ChunkMath.calcRelativeBlockPos(blockY, chunkFilterSize.y), - ChunkMath.calcRelativeBlockPos(blockZ, chunkFilterSize.z)); + Chunks.toRelative(blockX, chunkFilterSize.x), + Chunks.toRelative(blockY, chunkFilterSize.y), + Chunks.toRelative(blockZ, chunkFilterSize.z)); } @Override @@ -107,44 +108,39 @@ public byte getLight(Vector3i pos) { @Override public byte getSunlight(int blockX, int blockY, int blockZ) { - if (!blockRegion.encompasses(blockX, blockY, blockZ)) { + if (!blockRegion.contains(blockX, blockY, blockZ)) { return 0; } int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getSunlight(ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize)); + return chunks[chunkIndex].getSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); } @Override public byte getLight(int blockX, int blockY, int blockZ) { - if (!blockRegion.encompasses(blockX, blockY, blockZ)) { + if (!blockRegion.contains(blockX, blockY, blockZ)) { return 0; } int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getLight(ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize)); + return chunks[chunkIndex].getLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); } @Override - public void setBlock(Vector3i pos, Block type) { - setBlock(pos.x, pos.y, pos.z, type); + public void setBlock(Vector3ic pos, Block type) { + setBlock(pos.x(), pos.y(), pos.z(), type); } @Override public void setBlock(int blockX, int blockY, int blockZ, Block type) { - if (blockRegion.encompasses(blockX, blockY, blockZ)) { + if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setBlock(ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize), type); + chunks[chunkIndex].setBlock(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize), type); } else { logger.warn("Attempt to modify block outside of the view"); } } - @Override - public void setLight(Vector3i pos, byte light) { - setLight(pos.x, pos.y, pos.z, light); - } - @Override public void setLight(Vector3ic pos, byte light) { setLight(pos.x(), pos.y(), pos.z(), light); @@ -152,19 +148,14 @@ public void setLight(Vector3ic pos, byte light) { @Override public void setLight(int blockX, int blockY, int blockZ, byte light) { - if (blockRegion.encompasses(blockX, blockY, blockZ)) { + if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setLight(ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize), light); + chunks[chunkIndex].setLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); } else { logger.warn("Attempted to set light at a position not encompassed by the view"); } } - @Override - public void setSunlight(Vector3i pos, byte light) { - setSunlight(pos.x, pos.y, pos.z, light); - } - @Override public void setSunlight(Vector3ic pos, byte light) { setSunlight(pos.x(), pos.y(), pos.z(), light); @@ -172,63 +163,57 @@ public void setSunlight(Vector3ic pos, byte light) { @Override public void setSunlight(int blockX, int blockY, int blockZ, byte light) { - if (blockRegion.encompasses(blockX, blockY, blockZ)) { + if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setSunlight(ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize), light); + chunks[chunkIndex].setSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); } else { throw new IllegalStateException("Attempted to modify sunlight though an unlocked view"); } } @Override - public int getExtraData(int index, Vector3i pos) { - return getExtraData(index, pos.x, pos.y, pos.z); + public int getExtraData(int index, Vector3ic pos) { + return getExtraData(index, pos.x(), pos.y(), pos.z()); } @Override public int getExtraData(int index, int blockX, int blockY, int blockZ) { - if (!blockRegion.encompasses(blockX, blockY, blockZ)) { + if (!blockRegion.contains(blockX, blockY, blockZ)) { return 0; } int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getExtraData(index, ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize)); + return chunks[chunkIndex].getExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize)); } @Override - public void setExtraData(int index, Vector3i pos, int value) { - setExtraData(index, pos.x, pos.y, pos.z, value); + public void setExtraData(int index, Vector3ic pos, int value) { + setExtraData(index, pos.x(), pos.y(), pos.z(), value); } @Override public void setExtraData(int index, int blockX, int blockY, int blockZ, int value) { - if (blockRegion.encompasses(blockX, blockY, blockZ)) { + if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setExtraData(index, ChunkMath.calcRelativeBlockPos(blockX, blockY, blockZ, chunkFilterSize), value); + chunks[chunkIndex].setExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize), value); } else { throw new IllegalStateException("Attempted to modify extra data though an unlocked view"); } } @Override - public void setDirtyAround(Vector3i blockPos) { - for (Vector3i pos : ChunkMath.getChunkRegionAroundWorldPos(blockPos, 1)) { - chunks[pos.x + offset.x + chunkRegion.size().x * (pos.z + offset.z)].setDirty(true); + public void setDirtyAround(Vector3ic blockPos) { + BlockRegion tmp = new BlockRegion(blockPos).expand(1, 1, 1); + for (Vector3ic pos : Chunks.toChunkRegion(tmp, tmp)) { + chunks[pos.x() + offset.x + chunkRegion.getSizeX() * (pos.z() + offset.z)].setDirty(true); } } @Override - public void setDirtyAround(Region3i region) { - Vector3i minPos = new Vector3i(region.min()); - minPos.sub(1, 1, 1); - Vector3i maxPos = new Vector3i(region.max()); - maxPos.add(1, 1, 1); - - Vector3i minChunk = ChunkMath.calcChunkPos(minPos, chunkPower); - Vector3i maxChunk = ChunkMath.calcChunkPos(maxPos, chunkPower); - - for (Vector3i pos : Region3i.createFromMinMax(minChunk, maxChunk)) { - chunks[pos.x + offset.x + chunkRegion.size().x * (pos.z + offset.z)].setDirty(true); + public void setDirtyAround(BlockRegionc region) { + BlockRegion tmp = new BlockRegion(region).expand(1, 1, 1); + for (Vector3ic pos : Chunks.toChunkRegion(tmp, chunkPower, tmp)) { + chunks[pos.x() + offset.x + chunkRegion.getSizeX() * (pos.z() + offset.z)].setDirty(true); } } @@ -243,26 +228,30 @@ public boolean isValidView() { } protected int relChunkIndex(int x, int y, int z) { - return TeraMath.calculate3DArrayIndex(ChunkMath.calcChunkPos(x, chunkPower.x) + offset.x, - ChunkMath.calcChunkPos(y, chunkPower.y) + offset.y, - ChunkMath.calcChunkPos(z, chunkPower.z) + offset.z, chunkRegion.size()); + return TeraMath.calculate3DArrayIndex(Chunks.toChunkPos(x, chunkPower.x) + offset.x, + Chunks.toChunkPos(y, chunkPower.y) + offset.y, + Chunks.toChunkPos(z, chunkPower.z) + offset.z, JomlUtil.from(chunkRegion.getSize(new Vector3i()))); } public void setChunkSize(Vector3i chunkSize) { - this.chunkFilterSize = new Vector3i(TeraMath.ceilPowerOfTwo(chunkSize.x) - 1, TeraMath.ceilPowerOfTwo(chunkSize.y) - 1, TeraMath.ceilPowerOfTwo(chunkSize.z) - 1); + this.chunkFilterSize = new Vector3i(TeraMath.ceilPowerOfTwo(chunkSize.x) - 1, + TeraMath.ceilPowerOfTwo(chunkSize.y) - 1, + TeraMath.ceilPowerOfTwo(chunkSize.z) - 1); this.chunkPower = new Vector3i(TeraMath.sizeOfPower(chunkSize.x), TeraMath.sizeOfPower(chunkSize.y), TeraMath.sizeOfPower(chunkSize.z)); Vector3i blockMin = new Vector3i(); blockMin.sub(offset); blockMin.mul(chunkSize.x, chunkSize.y, chunkSize.z); - Vector3i blockSize = chunkRegion.size(); + Vector3i blockSize = chunkRegion.getSize(new Vector3i()); blockSize.mul(chunkSize.x, chunkSize.y, chunkSize.z); - this.blockRegion = Region3i.createFromMinAndSize(blockMin, blockSize); + this.blockRegion.setPosition(blockMin).setSize(blockSize); + } @Override - public Vector3i toWorldPos(Vector3i localPos) { - return new Vector3i(localPos.x + (offset.x + chunkRegion.min().x) * ChunkConstants.SIZE_X, localPos.y + (offset.y + chunkRegion.min().y) * ChunkConstants.SIZE_Y, - localPos.z + (offset.z + chunkRegion.min().z) * ChunkConstants.SIZE_Z); + public Vector3i toWorldPos(Vector3ic localPos) { + return new Vector3i(localPos.x() + (offset.x + chunkRegion.minX()) * Chunks.SIZE_X, + localPos.y() + (offset.y + chunkRegion.minY()) * Chunks.SIZE_Y, + localPos.z() + (offset.z + chunkRegion.minZ()) * Chunks.SIZE_Z); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java b/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java index 33b82253cda..ddf23289a29 100644 --- a/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java +++ b/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java @@ -15,6 +15,7 @@ */ package org.terasology.world.propagation; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.internal.ChunkViewCore; @@ -68,7 +69,7 @@ public void setValueAt(Vector3i pos, byte value) { @Override public Block getBlockAt(Vector3i pos) { if (isInBounds(pos)) { - return chunkView.getBlock(pos); + return chunkView.getBlock(JomlUtil.from(pos)); } return null; } @@ -79,6 +80,6 @@ public Block getBlockAt(Vector3i pos) { * @param pos The position to check, in world coordinates */ public boolean isInBounds(Vector3i pos) { - return chunkView.getWorldRegion().encompasses(pos); + return chunkView.getWorldRegion().contains(JomlUtil.from(pos)); } } From 106c6ac41586fe09e1b40898a6db95c13922c908 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 9 Jan 2021 21:06:38 +0100 Subject: [PATCH 098/259] feat(JOML): deprecate TeraMath methods for `world.viewer.picker.*` (#4381) --- .../world/viewer/picker/CirclePicker.java | 27 ++++----------- .../world/viewer/picker/CirclePickerAll.java | 30 +++++----------- .../viewer/picker/CirclePickerClosest.java | 34 ++++++------------- .../world/viewer/picker/package-info.java | 17 ++-------- 4 files changed, 27 insertions(+), 81 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePicker.java b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePicker.java index 351fe7cd167..7edd78310c1 100644 --- a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePicker.java +++ b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePicker.java @@ -1,24 +1,11 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"){ } - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.viewer.picker; -import java.util.Set; +import org.joml.Vector2fc; -import org.terasology.math.geom.BaseVector2f; +import java.util.Set; /** * Retrieves a set of circular objects in the proximity of a given anchor point. @@ -27,9 +14,9 @@ public interface CirclePicker { void offer(float locX, float locY, T object); - - default void offer(BaseVector2f location, T object) { - offer(location.getX(), location.getY(), object); + + default void offer(Vector2fc location, T object) { + offer(location.x(), location.y(), object); } Set getAll(); diff --git a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerAll.java b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerAll.java index 491cd15f888..2b2ab0dfa05 100644 --- a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerAll.java +++ b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerAll.java @@ -1,23 +1,9 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"){ } - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.viewer.picker; -import org.terasology.math.geom.BaseVector2f; -import org.terasology.math.geom.Vector2f; +import org.joml.Vector2fc; import java.util.Collections; import java.util.HashSet; @@ -27,18 +13,18 @@ public class CirclePickerAll implements CirclePicker { private final Set hits = new HashSet<>(); - private final BaseVector2f cursor; + private final Vector2fc cursor; private final Function radiusFunc; - public CirclePickerAll(Vector2f cursor, Function radiusFunc) { - this.cursor = cursor; + public CirclePickerAll(Vector2fc cursor, Function radiusFunc) { + this.cursor = new org.joml.Vector2f(cursor); this.radiusFunc = radiusFunc; } @Override public void offer(float locX, float locY, T object) { - float dx = cursor.getX() - locX; - float dy = cursor.getY() - locY; + float dx = cursor.x() - locX; + float dy = cursor.y() - locY; float distSq = dx * dx + dy * dy; float rad = radiusFunc.apply(object).floatValue(); diff --git a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerClosest.java b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerClosest.java index 988b21b04ad..2c047a971e7 100644 --- a/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerClosest.java +++ b/engine/src/main/java/org/terasology/world/viewer/picker/CirclePickerClosest.java @@ -1,35 +1,21 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"){ } - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.viewer.picker; +import org.joml.Vector2fc; + import java.util.Collections; import java.util.Set; import java.util.function.Function; -import org.terasology.math.geom.BaseVector2f; -import org.terasology.math.geom.ImmutableVector2f; - /** * Retrieves the closest (circular) object from a collection of tested elements. * @param the object type */ public class CirclePickerClosest implements CirclePicker { - private final BaseVector2f cursor; + private final Vector2fc cursor; private final Function radiusFunc; private double minDistSq = Double.POSITIVE_INFINITY; @@ -39,7 +25,7 @@ public class CirclePickerClosest implements CirclePicker { * No minimum distance to the target is required * @param target the target location */ - public CirclePickerClosest(BaseVector2f target) { + public CirclePickerClosest(Vector2fc target) { this(target, ignored -> Double.POSITIVE_INFINITY); } @@ -48,15 +34,15 @@ public CirclePickerClosest(BaseVector2f target) { * @param target the target location * @param radiusFunc the radius function for each of the tested elements */ - public CirclePickerClosest(BaseVector2f target, Function radiusFunc) { - this.cursor = ImmutableVector2f.createOrUse(target); + public CirclePickerClosest(Vector2fc target, Function radiusFunc) { + this.cursor = new org.joml.Vector2f(target); this.radiusFunc = radiusFunc; } @Override public void offer(float locX, float locY, T object) { - float dx = cursor.getX() - locX; - float dy = cursor.getY() - locY; + float dx = cursor.x() - locX; + float dy = cursor.y() - locY; float distSq = dx * dx + dy * dy; float rad = radiusFunc.apply(object).floatValue(); diff --git a/engine/src/main/java/org/terasology/world/viewer/picker/package-info.java b/engine/src/main/java/org/terasology/world/viewer/picker/package-info.java index 2dd6944ac67..34b7dec5356 100644 --- a/engine/src/main/java/org/terasology/world/viewer/picker/package-info.java +++ b/engine/src/main/java/org/terasology/world/viewer/picker/package-info.java @@ -1,18 +1,5 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 @API package org.terasology.world.viewer.picker; From 86bb7905977537250432ecfa49346dd39302cfe6 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 9 Jan 2021 12:46:27 -0800 Subject: [PATCH 099/259] feat(JOML): migrate SectorUtils and Events (#4378) * feat(JOML): migrate SectorUtils and Events * test: fix failing tests by comparing vectors of the same type * fix: resolve LGTM error on incompatible types Co-authored-by: Tobias Nett --- .../LocalChunkProviderTest.java | 20 +++++++++---------- .../sectors/LoadedSectorUpdateEvent.java | 2 +- .../sectors/SectorRegionComponent.java | 2 +- .../entitySystem/sectors/SectorUtil.java | 17 +++++++++------- .../logic/debug/ChunkEventErrorLogger.java | 4 ++-- .../engine/VoxelLiquidWorldSystem.java | 12 ++++++----- .../physics/engine/VoxelWorldSystem.java | 12 ++++++----- .../rendering/world/WorldRendererSystem.java | 5 +++-- .../world/chunks/event/BeforeChunkUnload.java | 7 ++++--- .../world/chunks/event/OnChunkLoaded.java | 7 ++++--- .../LocalChunkProvider.java | 6 +++--- .../localChunkProvider/RelevanceSystem.java | 2 +- .../RemoteChunkProvider.java | 4 ++-- 13 files changed, 55 insertions(+), 45 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index bed4d0e816b..3a8e84a4144 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -128,8 +128,8 @@ void testGenerateSingleChunk() throws InterruptedException, ExecutionException, Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(1); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), - chunkPosition, + Assertions.assertEquals(JomlUtil.from(chunkPosition), + ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); }); } @@ -157,8 +157,8 @@ void testGenerateSingleChunkWithBlockLifeCycle() throws InterruptedException, Ex Event mustBeOnLoadedEvent = worldEventCaptor.getAllValues().get(1); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), - chunkPosition, + Assertions.assertEquals(JomlUtil.from(chunkPosition), + ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); }); @@ -192,8 +192,8 @@ void testLoadSingleChunk() throws InterruptedException, ExecutionException, Time Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(0); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), - chunkPosition, + Assertions.assertEquals(JomlUtil.from(chunkPosition), + ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); } @@ -218,8 +218,8 @@ void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, Execut Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(0); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), - chunkPosition, + Assertions.assertEquals(JomlUtil.from(chunkPosition), + ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); //TODO, it is not clear if the activate/addedBlocks event logic is correct. @@ -278,8 +278,8 @@ void testUnloadChunkAndDeactivationBlock() throws InterruptedException, TimeoutE Assertions.assertTrue(beforeChunkUnload.isPresent(), "World events must have BeforeChunkUnload event when chunk was unload"); - Assertions.assertEquals(beforeChunkUnload.get().getChunkPos(), - chunkPosition, + Assertions.assertEquals(JomlUtil.from(chunkPosition), + beforeChunkUnload.get().getChunkPos(), "Chunk position at event not expected"); //TODO, it is not clear if the activate/addedBlocks event logic is correct. diff --git a/engine/src/main/java/org/terasology/entitySystem/sectors/LoadedSectorUpdateEvent.java b/engine/src/main/java/org/terasology/entitySystem/sectors/LoadedSectorUpdateEvent.java index c2fdfc6b5c2..f133be590c4 100644 --- a/engine/src/main/java/org/terasology/entitySystem/sectors/LoadedSectorUpdateEvent.java +++ b/engine/src/main/java/org/terasology/entitySystem/sectors/LoadedSectorUpdateEvent.java @@ -15,8 +15,8 @@ */ package org.terasology.entitySystem.sectors; +import org.joml.Vector3i; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import java.util.Set; diff --git a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorRegionComponent.java b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorRegionComponent.java index 12a8d9b677b..83597156298 100644 --- a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorRegionComponent.java +++ b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorRegionComponent.java @@ -15,8 +15,8 @@ */ package org.terasology.entitySystem.sectors; +import org.joml.Vector3i; import org.terasology.entitySystem.Component; -import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import org.terasology.world.chunks.Chunk; diff --git a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java index 1f6e0b11351..fcffe5e2a14 100644 --- a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java +++ b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java @@ -15,13 +15,15 @@ */ package org.terasology.entitySystem.sectors; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.ChunkMath; -import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import java.util.Collection; import java.util.HashSet; @@ -57,7 +59,7 @@ public static SectorRegionComponent createSectorRegionComponent(Collection chunks) { regionComponent.chunks.addAll(chunks.stream() - .map(Chunk::getPosition) + .map(k -> k.getPosition(new Vector3i())) .collect(Collectors.toSet())); } @@ -90,12 +92,13 @@ public static void addChunksToRegionComponent(EntityRef entity, Collection getWatchedChunks(EntityRef entity) { Set chunks = new HashSet<>(); LocationComponent loc = entity.getComponent(LocationComponent.class); - if (loc != null&& !Float.isNaN(loc.getWorldPosition().x)) { - chunks.add(ChunkMath.calcChunkPos(loc.getWorldPosition())); + Vector3f position = loc.getWorldPosition(new Vector3f()); + if (position.isFinite()) { + chunks.add(Chunks.toChunkPos(position, new Vector3i())); } SectorRegionComponent regionComponent = entity.getComponent(SectorRegionComponent.class); if (regionComponent != null) { - chunks.addAll(regionComponent.chunks); + chunks.addAll(regionComponent.chunks); // potential leaky abstraction. component exposes its internal vectors } return chunks; } @@ -108,7 +111,7 @@ public static Set getWatchedChunks(EntityRef entity) { * @param chunkProvider the chunkProvider, so that it can check which chunks are loaded * @return whether the entity is watching no loaded chunks, or only the given chunk is loaded */ - public static boolean onlyWatchedChunk(EntityRef entity, Vector3i chunkPos, ChunkProvider chunkProvider) { + public static boolean onlyWatchedChunk(EntityRef entity, Vector3ic chunkPos, ChunkProvider chunkProvider) { Set readyChunks = getWatchedChunks(entity).stream() .filter(chunkProvider::isChunkReady) .collect(Collectors.toSet()); diff --git a/engine/src/main/java/org/terasology/logic/debug/ChunkEventErrorLogger.java b/engine/src/main/java/org/terasology/logic/debug/ChunkEventErrorLogger.java index 6cb8af4c038..15233783644 100644 --- a/engine/src/main/java/org/terasology/logic/debug/ChunkEventErrorLogger.java +++ b/engine/src/main/java/org/terasology/logic/debug/ChunkEventErrorLogger.java @@ -16,13 +16,13 @@ package org.terasology.logic.debug; import com.google.common.collect.Sets; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterSystem; -import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldComponent; import org.terasology.world.chunks.event.BeforeChunkUnload; import org.terasology.world.chunks.event.OnChunkLoaded; @@ -35,7 +35,7 @@ public class ChunkEventErrorLogger extends BaseComponentSystem { private static final Logger logger = LoggerFactory.getLogger(ChunkEventErrorLogger.class); - private Set loadedChunks = Sets.newHashSet(); + private Set loadedChunks = Sets.newHashSet(); @ReceiveEvent(components = {WorldComponent.class}) public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { diff --git a/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java b/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java index 78a0b34c3b6..8a5d8f2032e 100644 --- a/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java +++ b/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java @@ -27,11 +27,13 @@ import gnu.trove.set.hash.TShortHashSet; import org.joml.Matrix4f; import org.joml.Vector3f; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterSystem; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.physics.StandardCollisionGroup; import org.terasology.physics.bullet.BulletPhysics; @@ -130,8 +132,8 @@ public void onBlockChange(OnChangedBlock event, EntityRef entity) { */ @ReceiveEvent(components = WorldComponent.class) public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldEntity) { - Vector3i chunkPos = beforeChunkUnload.getChunkPos(); - wrapper.freeRegion(chunkPos.x, chunkPos.y, chunkPos.z); + Vector3ic chunkPos = beforeChunkUnload.getChunkPos(); + wrapper.freeRegion(chunkPos.x(), chunkPos.y(), chunkPos.z()); } /** @@ -141,8 +143,8 @@ public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldE */ @ReceiveEvent(components = WorldComponent.class) public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { - Vector3i chunkPos = chunkAvailable.getChunkPos(); - Chunk chunk = chunkProvider.getChunk(chunkPos); + Vector3ic chunkPos = chunkAvailable.getChunkPos(); + Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkPos)); ByteBuffer buffer = ByteBuffer.allocateDirect(2 * (ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z)); buffer.order(ByteOrder.nativeOrder()); @@ -156,6 +158,6 @@ public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { } } buffer.rewind(); - wrapper.setRegion(chunkPos.x, chunkPos.y, chunkPos.z, buffer.asShortBuffer()); + wrapper.setRegion(chunkPos.x(), chunkPos.y(), chunkPos.z(), buffer.asShortBuffer()); } } diff --git a/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java b/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java index 9f722fbb184..a6c0ad156f0 100644 --- a/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java +++ b/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java @@ -27,11 +27,13 @@ import gnu.trove.set.hash.TShortHashSet; import org.joml.Matrix4f; import org.joml.Vector3f; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterSystem; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.physics.StandardCollisionGroup; import org.terasology.physics.bullet.BulletPhysics; @@ -129,8 +131,8 @@ public void onBlockChange(OnChangedBlock event, EntityRef entity) { */ @ReceiveEvent(components = WorldComponent.class) public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldEntity) { - Vector3i chunkPos = beforeChunkUnload.getChunkPos(); - wrapper.freeRegion(chunkPos.x, chunkPos.y, chunkPos.z); + Vector3ic chunkPos = beforeChunkUnload.getChunkPos(); + wrapper.freeRegion(chunkPos.x(), chunkPos.y(), chunkPos.z()); } /** @@ -140,8 +142,8 @@ public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldE */ @ReceiveEvent(components = WorldComponent.class) public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { - Vector3i chunkPos = chunkAvailable.getChunkPos(); - Chunk chunk = chunkProvider.getChunk(chunkPos); + Vector3ic chunkPos = chunkAvailable.getChunkPos(); + Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkPos)); ByteBuffer buffer = ByteBuffer.allocateDirect(2 * (ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z)); buffer.order(ByteOrder.nativeOrder()); @@ -155,6 +157,6 @@ public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { } } buffer.rewind(); - wrapper.setRegion(chunkPos.x, chunkPos.y, chunkPos.z, buffer.asShortBuffer()); + wrapper.setRegion(chunkPos.x(), chunkPos.y(), chunkPos.z(), buffer.asShortBuffer()); } } diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRendererSystem.java b/engine/src/main/java/org/terasology/rendering/world/WorldRendererSystem.java index ca1df405061..4d387c7836b 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRendererSystem.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRendererSystem.java @@ -20,6 +20,7 @@ import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; +import org.terasology.math.JomlUtil; import org.terasology.registry.In; import org.terasology.world.WorldComponent; import org.terasology.world.chunks.event.BeforeChunkUnload; @@ -35,12 +36,12 @@ public class WorldRendererSystem extends BaseComponentSystem { @ReceiveEvent(components = WorldComponent.class) public void onChunkLoaded(OnChunkLoaded chunkLoaded, EntityRef entity) { - worldRenderer.onChunkLoaded(chunkLoaded.getChunkPos()); + worldRenderer.onChunkLoaded(JomlUtil.from(chunkLoaded.getChunkPos())); } @ReceiveEvent(components = WorldComponent.class) public void onChunkUnloaded(BeforeChunkUnload chunkUnloaded, EntityRef entity) { - worldRenderer.onChunkUnloaded(chunkUnloaded.getChunkPos()); + worldRenderer.onChunkUnloaded(JomlUtil.from(chunkUnloaded.getChunkPos())); } diff --git a/engine/src/main/java/org/terasology/world/chunks/event/BeforeChunkUnload.java b/engine/src/main/java/org/terasology/world/chunks/event/BeforeChunkUnload.java index a8af97be792..1036346d4ad 100644 --- a/engine/src/main/java/org/terasology/world/chunks/event/BeforeChunkUnload.java +++ b/engine/src/main/java/org/terasology/world/chunks/event/BeforeChunkUnload.java @@ -16,8 +16,9 @@ package org.terasology.world.chunks.event; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; /** */ @@ -25,11 +26,11 @@ public class BeforeChunkUnload implements Event { private Vector3i chunkPos = new Vector3i(); - public BeforeChunkUnload(Vector3i chunkPos) { + public BeforeChunkUnload(Vector3ic chunkPos) { this.chunkPos.set(chunkPos); } - public Vector3i getChunkPos() { + public Vector3ic getChunkPos() { return chunkPos; } } diff --git a/engine/src/main/java/org/terasology/world/chunks/event/OnChunkLoaded.java b/engine/src/main/java/org/terasology/world/chunks/event/OnChunkLoaded.java index dc004a98d4a..77ca9754381 100644 --- a/engine/src/main/java/org/terasology/world/chunks/event/OnChunkLoaded.java +++ b/engine/src/main/java/org/terasology/world/chunks/event/OnChunkLoaded.java @@ -16,19 +16,20 @@ package org.terasology.world.chunks.event; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; /** */ public class OnChunkLoaded implements Event { private Vector3i chunkPos = new Vector3i(); - public OnChunkLoaded(Vector3i chunkPos) { + public OnChunkLoaded(Vector3ic chunkPos) { this.chunkPos.set(chunkPos); } - public Vector3i getChunkPos() { + public Vector3ic getChunkPos() { return chunkPos; } } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index e5dd1a8f9c6..7d137fb6d86 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -241,7 +241,7 @@ private void processReadyChunk(final Chunk chunk) { worldEntity.send(new OnChunkGenerated(chunk.getPosition())); } - worldEntity.send(new OnChunkLoaded(chunk.getPosition())); + worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); } private void generateQueuedEntities(EntityStore store) { @@ -315,7 +315,7 @@ private boolean unloadChunkInternal(Vector3i pos) { return false; } - worldEntity.send(new BeforeChunkUnload(pos)); + worldEntity.send(new BeforeChunkUnload(JomlUtil.from(pos))); storageManager.deactivateChunk(chunk); chunk.dispose(); @@ -432,7 +432,7 @@ public void purgeWorld() { loadingPipeline.shutdown(); unloadRequestTaskMaster.shutdown(new ChunkUnloadRequest(), true); getAllChunks().stream().filter(ManagedChunk::isReady).forEach(chunk -> { - worldEntity.send(new BeforeChunkUnload(chunk.getPosition())); + worldEntity.send(new BeforeChunkUnload(chunk.getPosition(new org.joml.Vector3i()))); storageManager.deactivateChunk(chunk); chunk.dispose(); }); diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java index 60a6be0a6a4..abf107e2d4f 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java @@ -81,7 +81,7 @@ public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { @ReceiveEvent(components = WorldComponent.class) public void onRemoveChunk(BeforeChunkUnload chunkUnloadEvent, EntityRef worldEntity) { for (ChunkRelevanceRegion region : regions.values()) { - region.chunkUnloaded(chunkUnloadEvent.getChunkPos()); + region.chunkUnloaded(JomlUtil.from(chunkUnloadEvent.getChunkPos())); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 9f9c5aa707e..6032129dddb 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -114,7 +114,7 @@ public void update() { if (listener != null) { listener.onChunkReady(chunk.getPosition()); } - worldEntity.send(new OnChunkLoaded(chunk.getPosition())); + worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); } } @@ -124,7 +124,7 @@ private void checkForUnload() { for (Vector3i pos : positions) { Chunk removed = chunkCache.remove(pos); if (removed != null && !removed.isReady()) { - worldEntity.send(new BeforeChunkUnload(pos)); + worldEntity.send(new BeforeChunkUnload(JomlUtil.from(pos))); removed.dispose(); } } From bd086aa3a0bebe36e5c526cf41a9f301e2126daa Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 9 Jan 2021 22:15:16 +0100 Subject: [PATCH 100/259] feat(JOML): migrate `logic.ai.*` (#4382) --- .../logic/ai/HierarchicalAIComponent.java | 2 +- .../logic/ai/HierarchicalAISystem.java | 75 ++++++++----------- .../logic/ai/SimpleAIComponent.java | 2 +- .../terasology/logic/ai/SimpleAISystem.java | 16 ++-- 4 files changed, 39 insertions(+), 56 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAIComponent.java b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAIComponent.java index babeb166d9d..07a5b783d34 100644 --- a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAIComponent.java +++ b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAIComponent.java @@ -16,7 +16,7 @@ package org.terasology.logic.ai; import org.terasology.entitySystem.Component; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; /** */ diff --git a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java index 8ec92d41805..c0bbaad2462 100644 --- a/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java +++ b/engine/src/main/java/org/terasology/logic/ai/HierarchicalAISystem.java @@ -15,6 +15,8 @@ */ package org.terasology.logic.ai; +import org.joml.Vector3f; +import org.joml.Vector3fc; import org.terasology.engine.Time; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -28,8 +30,6 @@ import org.terasology.logic.characters.events.HorizontalCollisionEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; import org.terasology.utilities.random.Random; @@ -40,8 +40,7 @@ * */ @RegisterSystem(RegisterMode.AUTHORITY) -public class HierarchicalAISystem extends BaseComponentSystem implements - UpdateSubscriberSystem { +public class HierarchicalAISystem extends BaseComponentSystem implements UpdateSubscriberSystem { @In private WorldProvider worldProvider; @@ -62,20 +61,19 @@ public class HierarchicalAISystem extends BaseComponentSystem implements @Override public void update(float delta) { + Vector3f tmp = new Vector3f(); for (EntityRef entity : entityManager.getEntitiesWith( - HierarchicalAIComponent.class, CharacterMovementComponent.class, - LocationComponent.class)) { - LocationComponent location = entity - .getComponent(LocationComponent.class); - Vector3f worldPos = location.getWorldPosition(); + HierarchicalAIComponent.class, CharacterMovementComponent.class, LocationComponent.class)) { + LocationComponent location = entity.getComponent(LocationComponent.class); + location.getWorldPosition(tmp); // Skip this AI if not in a loaded chunk - if (!worldProvider.isBlockRelevant(worldPos)) { + if (!worldProvider.isBlockRelevant(tmp)) { continue; } // goto Hierarchical system - loop(entity, location, worldPos); + loop(entity, location, tmp); } } @@ -86,10 +84,8 @@ public void update(float delta) { * @param location * @param worldPos */ - private void loop(EntityRef entity, LocationComponent location, - Vector3f worldPos) { - HierarchicalAIComponent ai = entity - .getComponent(HierarchicalAIComponent.class); + private void loop(EntityRef entity, LocationComponent location, Vector3fc worldPos) { + HierarchicalAIComponent ai = entity.getComponent(HierarchicalAIComponent.class); long tempTime = time.getGameTimeInMs(); //TODO remove next long lastAttack = 0; @@ -111,11 +107,9 @@ private void loop(EntityRef entity, LocationComponent location, // find player position // TODO: shouldn't use local player, need some way to find nearest - // player if (localPlayer != null) { - Vector3f dist = new Vector3f(worldPos); - dist.sub(localPlayer.getPosition()); - double distanceToPlayer = dist.lengthSquared(); + final Vector3f playerPosition = localPlayer.getPosition(new Vector3f()); + double distanceToPlayer = worldPos.distanceSquared(playerPosition); ai.inDanger = false; if (ai.dieIfPlayerFar && distanceToPlayer > ai.dieDistance) { @@ -126,19 +120,15 @@ private void loop(EntityRef entity, LocationComponent location, if (tempTime - ai.lastChangeOfDangerAt > dangerChangeTime) { dangerChangeTime = (long) (ai.dangerUpdateTime * random.nextDouble() * ai.hectic); if (ai.hunter) { - if (distanceToPlayer > ai.playerdistance - && distanceToPlayer < ai.playerSense) { + if (distanceToPlayer > ai.playerdistance && distanceToPlayer < ai.playerSense) { // Head to player - Vector3f tempTarget = localPlayer.getPosition(); if (ai.forgiving != 0) { - ai.movementTarget.set(new Vector3f( - tempTarget.x + random.nextFloat(-ai.forgiving, ai.forgiving), - tempTarget.y + random.nextFloat(-ai.forgiving, ai.forgiving), - tempTarget.z + random.nextFloat(-ai.forgiving, ai.forgiving) - )); - } else { - ai.movementTarget.set(tempTarget); + playerPosition.add( + random.nextFloat(-ai.forgiving, ai.forgiving), + random.nextFloat(-ai.forgiving, ai.forgiving), + random.nextFloat(-ai.forgiving, ai.forgiving)); } + ai.movementTarget.set(playerPosition); ai.inDanger = true; entity.saveComponent(ai); @@ -205,22 +195,19 @@ private void loop(EntityRef entity, LocationComponent location, } } - Vector3f targetDirection = new Vector3f(); - targetDirection.sub(ai.movementTarget, worldPos); + Vector3f targetDirection = ai.movementTarget.sub(worldPos, new Vector3f()); targetDirection.normalize(); drive.set(targetDirection); float yaw = (float) Math.atan2(targetDirection.x, targetDirection.z); - entity.send(new CharacterMoveInputEvent(0, 0, yaw, JomlUtil.from(drive), false, false, time.getGameDeltaInMs())); + entity.send(new CharacterMoveInputEvent(0, 0, yaw, drive, false, false, false, time.getGameDeltaInMs())); entity.saveComponent(location); - // System.out.print("\Destination set: " + targetDirection.x + ":" +targetDirection.z + "\n"); - // System.out.print("\nI am: " + worldPos.x + ":" + worldPos.z + "\n"); ai.lastProgressedUpdateAt = time.getGameTimeInMs(); } private void runAway(EntityRef entity, HierarchicalAIComponent ai) { - Vector3f tempTarget = localPlayer.getPosition(); + Vector3f tempTarget = localPlayer.getPosition(new Vector3f()); if (ai.forgiving != 0) { ai.movementTarget.set(new Vector3f( -tempTarget.x + random.nextFloat(-ai.forgiving, ai.forgiving), @@ -237,22 +224,22 @@ private void runAway(EntityRef entity, HierarchicalAIComponent ai) { ai.inDanger = true; } - private void randomWalk(Vector3f worldPos, HierarchicalAIComponent ai) { + private void randomWalk(Vector3fc worldPos, HierarchicalAIComponent ai) { // if ai flies if (ai.flying) { float targetY = 0; do { - targetY = worldPos.y + random.nextFloat(-100.0f, 100.0f); + targetY = worldPos.y() + random.nextFloat(-100.0f, 100.0f); } while (targetY > ai.maxAltitude); ai.movementTarget.set( - worldPos.x + random.nextFloat(-500.0f, 500.0f), + worldPos.x() + random.nextFloat(-500.0f, 500.0f), targetY, - worldPos.z + random.nextFloat(-500.0f, 500.0f)); + worldPos.z() + random.nextFloat(-500.0f, 500.0f)); } else { ai.movementTarget.set( - worldPos.x + random.nextFloat(-500.0f, 500.0f), - worldPos.y, - worldPos.z + random.nextFloat(-500.0f, 500.0f)); + worldPos.x() + random.nextFloat(-500.0f, 500.0f), + worldPos.y(), + worldPos.z() + random.nextFloat(-500.0f, 500.0f)); } ai.lastChangeOfDirectionAt = time.getGameTimeInMs(); } @@ -264,9 +251,7 @@ private boolean foodInFront() { //TODO change eating thingy to use this @ReceiveEvent(components = {HierarchicalAIComponent.class}) - public void onBump(HorizontalCollisionEvent event, EntityRef entity) { - CharacterMovementComponent moveComp = entity - .getComponent(CharacterMovementComponent.class); + public void onBump(HorizontalCollisionEvent event, EntityRef entity, CharacterMovementComponent moveComp) { if (moveComp != null && moveComp.grounded) { moveComp.jump = true; entity.saveComponent(moveComp); diff --git a/engine/src/main/java/org/terasology/logic/ai/SimpleAIComponent.java b/engine/src/main/java/org/terasology/logic/ai/SimpleAIComponent.java index 42949db0c74..7bd548f98e9 100644 --- a/engine/src/main/java/org/terasology/logic/ai/SimpleAIComponent.java +++ b/engine/src/main/java/org/terasology/logic/ai/SimpleAIComponent.java @@ -16,7 +16,7 @@ package org.terasology.logic.ai; import org.terasology.entitySystem.Component; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; /** */ diff --git a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java index a0a07043e5c..94f274a8684 100644 --- a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java +++ b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java @@ -15,6 +15,7 @@ */ package org.terasology.logic.ai; +import org.joml.Vector3f; import org.terasology.engine.Time; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -28,8 +29,6 @@ import org.terasology.logic.characters.events.HorizontalCollisionEvent; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.utilities.random.FastRandom; import org.terasology.utilities.random.Random; @@ -54,7 +53,7 @@ public class SimpleAISystem extends BaseComponentSystem implements UpdateSubscri public void update(float delta) { for (EntityRef entity : entityManager.getEntitiesWith(SimpleAIComponent.class, CharacterMovementComponent.class, LocationComponent.class)) { LocationComponent location = entity.getComponent(LocationComponent.class); - Vector3f worldPos = location.getWorldPosition(); + Vector3f worldPos = location.getWorldPosition(new Vector3f()); // Skip this AI if not in a loaded chunk if (!worldProvider.isBlockRelevant(worldPos)) { @@ -65,13 +64,12 @@ public void update(float delta) { Vector3f drive = new Vector3f(); // TODO: shouldn't use local player, need some way to find nearest player if (localPlayer != null) { - Vector3f dist = new Vector3f(worldPos); - dist.sub(localPlayer.getPosition()); - double distanceToPlayer = dist.lengthSquared(); + final Vector3f playerPosition = localPlayer.getPosition(new Vector3f()); + double distanceToPlayer = worldPos.distanceSquared(playerPosition); if (distanceToPlayer > 6 && distanceToPlayer < 16) { // Head to player - ai.movementTarget.set(localPlayer.getPosition()); + ai.movementTarget.set(playerPosition); ai.followingPlayer = true; entity.saveComponent(ai); } else { @@ -90,10 +88,10 @@ public void update(float delta) { drive.set(targetDirection); float yaw = (float) Math.atan2(targetDirection.x, targetDirection.z); - location.getLocalRotation().set(new Vector3f(0, 1, 0), yaw); + location.getLocalRotation().set(0, 1, 0, yaw); entity.saveComponent(location); } - entity.send(new CharacterMoveInputEvent(0, 0, 0, JomlUtil.from(drive), false, false, time.getGameDeltaInMs())); + entity.send(new CharacterMoveInputEvent(0, 0, 0, drive, false, false, false, time.getGameDeltaInMs())); } } From 4bc4eceb0893e1040e4b38bfa92b8873422d4088 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 9 Jan 2021 23:59:28 +0100 Subject: [PATCH 101/259] feat(JOML): migrate `world.zones.*` (#4383) --- .../terasology/world/generation/Border3D.java | 2 -- .../java/org/terasology/world/zones/Zone.java | 29 +++++++++---------- .../terasology/world/zones/ZonePlugin.java | 6 ++-- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/generation/Border3D.java b/engine/src/main/java/org/terasology/world/generation/Border3D.java index 62b818c21b2..8aaae960e04 100644 --- a/engine/src/main/java/org/terasology/world/generation/Border3D.java +++ b/engine/src/main/java/org/terasology/world/generation/Border3D.java @@ -16,9 +16,7 @@ package org.terasology.world.generation; import com.google.common.base.Preconditions; -import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.math.geom.Rect2i; import org.terasology.world.block.BlockArea; import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; diff --git a/engine/src/main/java/org/terasology/world/zones/Zone.java b/engine/src/main/java/org/terasology/world/zones/Zone.java index adb75e4249c..dc4d8636f9d 100644 --- a/engine/src/main/java/org/terasology/world/zones/Zone.java +++ b/engine/src/main/java/org/terasology/world/zones/Zone.java @@ -15,12 +15,13 @@ */ package org.terasology.world.zones; -import org.terasology.math.geom.BaseVector3i; -import org.terasology.math.geom.ImmutableVector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.module.sandbox.API; import org.terasology.rendering.nui.layers.mainMenu.preview.FacetLayerPreview; import org.terasology.rendering.nui.layers.mainMenu.preview.PreviewGenerator; import org.terasology.world.block.Block; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.CoreChunk; import org.terasology.world.generation.EntityBuffer; import org.terasology.world.generation.EntityProvider; @@ -38,10 +39,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.terasology.world.chunks.ChunkConstants.SIZE_X; -import static org.terasology.world.chunks.ChunkConstants.SIZE_Y; -import static org.terasology.world.chunks.ChunkConstants.SIZE_Z; - /** * A region in the world with its own rasterization and world preview properties. * @@ -76,12 +73,12 @@ public Zone(String name, BooleanSupplier regionFunction) { this(name, (pos, region) -> regionFunction.getAsBoolean()); } - public Zone(String name, Predicate regionFunction) { + public Zone(String name, Predicate regionFunction) { this(name, (pos, region) -> regionFunction.test(pos)); } - public Zone(String name, BiPredicate regionFunction) { - this(name, (x, y, z, region) -> regionFunction.test(new ImmutableVector3i(x, y, z), region)); + public Zone(String name, BiPredicate regionFunction) { + this(name, (x, y, z, region) -> regionFunction.test(new Vector3i(x, y, z), region)); } /** @@ -124,7 +121,7 @@ public void process(Region region, EntityBuffer buffer) { */ @Override public void generateChunk(CoreChunk chunk, Region chunkRegion) { - Block[][][] savedBlocks = new Block[SIZE_X][SIZE_Y][SIZE_Z]; + Block[][][] savedBlocks = new Block[Chunks.SIZE_X][Chunks.SIZE_Y][Chunks.SIZE_Z]; boolean changeAllBlocks = true; boolean saveAllBlocks = true; @@ -133,9 +130,9 @@ public void generateChunk(CoreChunk chunk, Region chunkRegion) { int offsetZ = chunk.getChunkWorldOffsetZ(); //Save the blocks that aren't in the zone - for (int x = 0; x < SIZE_X; x++) { - for (int y = 0; y < SIZE_Y; y++) { - for (int z = 0; z < SIZE_Z; z++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int y = 0; y regionFunction) { + public ZonePlugin(String name, Predicate regionFunction) { super(name, regionFunction); } - public ZonePlugin(String name, BiPredicate regionFunction) { + public ZonePlugin(String name, BiPredicate regionFunction) { super(name, regionFunction); } From 44e718ee665b606574e7232069b8f0e8ad44bb39 Mon Sep 17 00:00:00 2001 From: jdrueckert Date: Sun, 10 Jan 2021 10:28:51 +0100 Subject: [PATCH 102/259] feat(JOML): migrate `RelevanceRegionComponent` (#4385) --- .../logic/players/PlayerSystem.java | 4 +- .../ServerViewDistanceSystem.java | 2 +- .../world/RelevanceRegionComponent.java | 4 +- .../chunks/internal/ChunkRelevanceRegion.java | 66 ++++++++++--------- .../LocalChunkProvider.java | 6 +- .../localChunkProvider/RelevanceSystem.java | 35 +++++----- 6 files changed, 58 insertions(+), 59 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java index e8271b7e8dc..98057955e94 100644 --- a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java @@ -195,7 +195,7 @@ private void updateRelevanceEntity(EntityRef entity, Vector3ic chunkDistance) { //RelevanceRegionComponent relevanceRegion = new RelevanceRegionComponent(); //relevanceRegion.distance = chunkDistance; //entity.saveComponent(relevanceRegion); - relevanceSystem.updateRelevanceEntityDistance(entity, JomlUtil.from(chunkDistance)); + relevanceSystem.updateRelevanceEntityDistance(entity, chunkDistance); } private void removeRelevanceEntity(EntityRef entity) { @@ -208,7 +208,7 @@ private void addRelevanceEntity(EntityRef entity, Vector3ic chunkDistance, Clien //RelevanceRegionComponent relevanceRegion = new RelevanceRegionComponent(); //relevanceRegion.distance = chunkDistance; //entity.addComponent(relevanceRegion); - relevanceSystem.addRelevanceEntity(entity, JomlUtil.from(chunkDistance), owner); + relevanceSystem.addRelevanceEntity(entity, chunkDistance, owner); } @ReceiveEvent(components = ClientComponent.class) diff --git a/engine/src/main/java/org/terasology/rendering/world/viewDistance/ServerViewDistanceSystem.java b/engine/src/main/java/org/terasology/rendering/world/viewDistance/ServerViewDistanceSystem.java index dcab8f77959..ef33ed21dc1 100644 --- a/engine/src/main/java/org/terasology/rendering/world/viewDistance/ServerViewDistanceSystem.java +++ b/engine/src/main/java/org/terasology/rendering/world/viewDistance/ServerViewDistanceSystem.java @@ -44,7 +44,7 @@ public void onChangeViewDistanceChanged(ViewDistanceChangedEvent request, Entity Client client = networkSystem.getOwner(entity); if (client != null) { client.setViewDistanceMode(request.getNewViewRange()); - relevanceSystem.updateRelevanceEntityDistance(entity, JomlUtil.from(client.getViewDistance().getChunkDistance())); + relevanceSystem.updateRelevanceEntityDistance(entity, client.getViewDistance().getChunkDistance()); } } diff --git a/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java b/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java index ea8e0753e75..ba10bf1a4df 100644 --- a/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java +++ b/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java @@ -15,13 +15,13 @@ */ package org.terasology.world; +import org.joml.Vector3i; import org.terasology.entitySystem.Component; -import org.terasology.math.geom.Vector3i; /** */ public class RelevanceRegionComponent implements Component { - public Vector3i distance = Vector3i.one(); + public Vector3i distance = new Vector3i(1, 1, 1); } diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java index 056b875eab5..16ecbb1de44 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java @@ -18,15 +18,18 @@ import com.google.common.base.Objects; import com.google.common.collect.Sets; +import org.joml.Vector3f; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.location.LocationComponent; import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkRegionListener; +import org.terasology.world.chunks.Chunks; import java.util.Iterator; import java.util.Set; @@ -38,22 +41,22 @@ public class ChunkRelevanceRegion { private Vector3i relevanceDistance = new Vector3i(); private boolean dirty; private Vector3i center = new Vector3i(); - private Region3i currentRegion = Region3i.empty(); - private Region3i previousRegion = Region3i.empty(); + private BlockRegion currentRegion = new BlockRegion(BlockRegion.INVALID); + private BlockRegion previousRegion = new BlockRegion(BlockRegion.INVALID); private ChunkRegionListener listener; - private Set relevantChunks = Sets.newLinkedHashSet(); + private Set relevantChunks = Sets.newLinkedHashSet(); - public ChunkRelevanceRegion(EntityRef entity, Vector3i relevanceDistance) { + public ChunkRelevanceRegion(EntityRef entity, Vector3ic relevanceDistance) { this.entity = entity; this.relevanceDistance.set(relevanceDistance); LocationComponent loc = entity.getComponent(LocationComponent.class); - if (loc == null||Float.isNaN(loc.getWorldPosition().x)) { + if (loc == null||Float.isNaN(loc.getWorldPosition(new Vector3f()).x)) { dirty = false; } else { - center.set(ChunkMath.calcChunkPos(loc.getWorldPosition())); + center.set(Chunks.toChunkPos(loc.getWorldPosition(new Vector3f()), new Vector3i())); currentRegion = calculateRegion(); dirty = true; } @@ -63,7 +66,7 @@ public Vector3i getCenter() { return center; } - public void setRelevanceDistance(Vector3i distance) { + public void setRelevanceDistance(Vector3ic distance) { if (!distance.equals(this.relevanceDistance)) { reviewRelevantChunks(distance); this.relevanceDistance.set(distance); @@ -72,14 +75,14 @@ public void setRelevanceDistance(Vector3i distance) { } } - private void reviewRelevantChunks(Vector3i distance) { - Vector3i extents = new Vector3i(distance.x / 2, distance.y / 2, distance.z / 2); - Region3i retainRegion = Region3i.createFromCenterExtents(center, extents); - Iterator iter = relevantChunks.iterator(); + private void reviewRelevantChunks(Vector3ic distance) { + Vector3i extents = new Vector3i(distance.x() / 2, distance.y() / 2, distance.z() / 2); + BlockRegion retainRegion = new BlockRegion(center).expand(extents); + Iterator iter = relevantChunks.iterator(); while (iter.hasNext()) { - Vector3i pos = iter.next(); - if (!retainRegion.encompasses(pos)) { - sendChunkIrrelevant(JomlUtil.from(pos)); + Vector3ic pos = iter.next(); + if (!retainRegion.contains(pos)) { + sendChunkIrrelevant(pos); iter.remove(); } } @@ -98,11 +101,11 @@ public void setUpToDate() { previousRegion = currentRegion; } - public Region3i getCurrentRegion() { + public BlockRegion getCurrentRegion() { return currentRegion; } - public Region3i getPreviousRegion() { + public BlockRegion getPreviousRegion() { return previousRegion; } @@ -120,19 +123,19 @@ public void update() { } } - private Region3i calculateRegion() { + private BlockRegion calculateRegion() { LocationComponent loc = entity.getComponent(LocationComponent.class); - if (loc != null&& !Float.isNaN(loc.getWorldPosition().x)) { + if (loc != null&& !Float.isNaN(loc.getWorldPosition(new Vector3f()).x)) { Vector3i extents = new Vector3i(relevanceDistance.x / 2, relevanceDistance.y / 2, relevanceDistance.z / 2); - return Region3i.createFromCenterExtents(ChunkMath.calcChunkPos(loc.getWorldPosition()), extents); + return new BlockRegion(Chunks.toChunkPos(loc.getWorldPosition(new Vector3f()), new Vector3i())).expand(extents); } - return Region3i.empty(); + return new BlockRegion(BlockRegion.INVALID); } private Vector3i calculateCenter() { LocationComponent loc = entity.getComponent(LocationComponent.class); - if (loc != null && !Float.isNaN(loc.getWorldPosition().x)) { - return ChunkMath.calcChunkPos(loc.getWorldPosition()); + if (loc != null && !Float.isNaN(loc.getWorldPosition(new Vector3f()).x)) { + return Chunks.toChunkPos(loc.getWorldPosition(new Vector3f()), new Vector3i()); } return new Vector3i(); } @@ -181,8 +184,8 @@ public int hashCode() { * chunks as relevant even when no light calculation has been performed yet. */ public void checkIfChunkIsRelevant(Chunk chunk) { - if (currentRegion.encompasses(chunk.getPosition()) && !relevantChunks.contains(chunk.getPosition())) { - relevantChunks.add(chunk.getPosition()); + if (currentRegion.contains(chunk.getPosition(new Vector3i())) && !relevantChunks.contains(chunk.getPosition(new Vector3i()))) { + relevantChunks.add(chunk.getPosition(new Vector3i())); sendChunkRelevant(chunk); } } @@ -191,16 +194,15 @@ public Iterable getNeededChunks() { return NeededChunksIterator::new; } - public void chunkUnloaded(Vector3i pos) { + public void chunkUnloaded(Vector3ic pos) { if (relevantChunks.contains(pos)) { relevantChunks.remove(pos); - sendChunkIrrelevant(JomlUtil.from(pos)); + sendChunkIrrelevant(pos); } } private class NeededChunksIterator implements Iterator { Vector3i nextChunkPos; - Iterator regionPositions = currentRegion.iterator(); NeededChunksIterator() { calculateNext(); @@ -225,10 +227,10 @@ public void remove() { private void calculateNext() { nextChunkPos = null; - while (regionPositions.hasNext() && nextChunkPos == null) { - Vector3i candidate = regionPositions.next(); - if (!relevantChunks.contains(candidate)) { - nextChunkPos = candidate; + for (Vector3ic regionPosition : currentRegion) { + if (!relevantChunks.contains(regionPosition)) { + nextChunkPos = new Vector3i(regionPosition); + return; } } } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 7d137fb6d86..65f49703952 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -289,7 +289,7 @@ private void checkForUnload() { loadingPipeline.getProcessingPosition().iterator()); while (iterator.hasNext()) { org.joml.Vector3ic pos = iterator.next(); - boolean keep = relevanceSystem.isChunkInRegions(JomlUtil.from(pos)); // TODO: move it to relevance system. + boolean keep = relevanceSystem.isChunkInRegions(pos); // TODO: move it to relevance system. if (!keep && unloadChunkInternal(JomlUtil.from(pos))) { iterator.remove(); if (++unloaded >= UNLOAD_PER_FRAME) { @@ -459,8 +459,8 @@ public void purgeWorld() { ChunkMonitor.fireChunkProviderInitialized(this); for (ChunkRelevanceRegion chunkRelevanceRegion : relevanceSystem.getRegions()) { - for (Vector3i pos : chunkRelevanceRegion.getCurrentRegion()) { - createOrLoadChunk(pos); + for (Vector3ic pos : chunkRelevanceRegion.getCurrentRegion()) { + createOrLoadChunk(JomlUtil.from(pos)); } chunkRelevanceRegion.setUpToDate(); } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java index abf107e2d4f..5a52abc3558 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java @@ -3,6 +3,8 @@ package org.terasology.world.chunks.localChunkProvider; import com.google.common.collect.Maps; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.lifecycleEvents.BeforeDeactivateComponent; import org.terasology.entitySystem.entity.lifecycleEvents.OnActivatedComponent; @@ -11,7 +13,6 @@ import org.terasology.entitySystem.systems.UpdateSubscriberSystem; import org.terasology.logic.location.LocationComponent; import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.Activity; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.world.RelevanceRegionComponent; @@ -43,7 +44,7 @@ */ public class RelevanceSystem implements UpdateSubscriberSystem { - private static final Vector3i UNLOAD_LEEWAY = Vector3i.one(); + private static final Vector3i UNLOAD_LEEWAY = new Vector3i(1, 1, 1); private final ReadWriteLock regionLock = new ReentrantReadWriteLock(); private final Map regions = Maps.newHashMap(); private final LocalChunkProvider chunkProvider; @@ -81,7 +82,7 @@ public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { @ReceiveEvent(components = WorldComponent.class) public void onRemoveChunk(BeforeChunkUnload chunkUnloadEvent, EntityRef worldEntity) { for (ChunkRelevanceRegion region : regions.values()) { - region.chunkUnloaded(JomlUtil.from(chunkUnloadEvent.getChunkPos())); + region.chunkUnloaded(chunkUnloadEvent.getChunkPos()); } } @@ -91,7 +92,7 @@ public void onRemoveChunk(BeforeChunkUnload chunkUnloadEvent, EntityRef worldEnt * @param entity entity for update distance. * @param distance new distance for setting to entity's region. */ - public void updateRelevanceEntityDistance(EntityRef entity, Vector3i distance) { + public void updateRelevanceEntityDistance(EntityRef entity, Vector3ic distance) { regionLock.readLock().lock(); try { ChunkRelevanceRegion region = regions.get(entity); @@ -130,7 +131,7 @@ private void updateRelevance() { if (chunk != null) { chunkRelevanceRegion.checkIfChunkIsRelevant(chunk); } else { - chunkProvider.createOrLoadChunk(pos); + chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); } } chunkRelevanceRegion.setUpToDate(); @@ -147,7 +148,7 @@ private void updateRelevance() { * @param distance region's distance. * @param listener chunk relevance listener. */ - public void addRelevanceEntity(EntityRef entity, Vector3i distance, ChunkRegionListener listener) { + public void addRelevanceEntity(EntityRef entity, Vector3ic distance, ChunkRegionListener listener) { if (!entity.exists()) { return; } @@ -180,7 +181,7 @@ public void addRelevanceEntity(EntityRef entity, Vector3i distance, ChunkRegionL if (chunk != null) { region.checkIfChunkIsRelevant(chunk); } else { - chunkProvider.createOrLoadChunk(pos); + chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); } } ); @@ -192,9 +193,9 @@ public void addRelevanceEntity(EntityRef entity, Vector3i distance, ChunkRegionL * @param pos chunk's position * @return {@code true} if chunk in regions, otherwise {@code false} */ - public boolean isChunkInRegions(Vector3i pos) { + public boolean isChunkInRegions(Vector3ic pos) { for (ChunkRelevanceRegion region : regions.values()) { - if (region.getCurrentRegion().expand(UNLOAD_LEEWAY).encompasses(pos)) { + if (region.getCurrentRegion().expand(UNLOAD_LEEWAY).contains(pos)) { return true; } } @@ -248,14 +249,14 @@ public void shutdown() { // ignore } - private int regionsDistanceScore(Vector3i chunk) { + private int regionsDistanceScore(Vector3ic chunk) { int score = Integer.MAX_VALUE; regionLock.readLock().lock(); try { for (ChunkRelevanceRegion region : regions.values()) { - int dist = distFromRegion(chunk, region.getCenter()); + int dist = (int) chunk.gridDistance(region.getCenter()); if (dist < score) { score = dist; } @@ -269,10 +270,6 @@ private int regionsDistanceScore(Vector3i chunk) { } } - private int distFromRegion(Vector3i pos, Vector3i regionCenter) { - return pos.gridDistance(regionCenter); - } - /** * Compare ChunkTasks by distance from region's centers. */ @@ -284,7 +281,7 @@ public int compare(Future o1, Future o2) { } private int score(PositionFuture task) { - return RelevanceSystem.this.regionsDistanceScore(JomlUtil.from(task.getPosition())); + return RelevanceSystem.this.regionsDistanceScore(task.getPosition()); } } @@ -292,14 +289,14 @@ private int score(PositionFuture task) { /** * Compare ChunkTasks by distance from region's centers. */ - private class PositionRelevanceComparator implements Comparator { + private class PositionRelevanceComparator implements Comparator { @Override - public int compare(Vector3i o1, Vector3i o2) { + public int compare(Vector3ic o1, Vector3ic o2) { return score(o1) - score(o2); } - private int score(Vector3i position) { + private int score(Vector3ic position) { return RelevanceSystem.this.regionsDistanceScore(position); } } From cf1a7fd8ce15e6ae0b3ad6524d4990c6ed27b115 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 10 Jan 2021 06:28:20 -0800 Subject: [PATCH 103/259] feat(JOML): migrate ChunkProvider#getLocalView (#4388) --- .../src/main/java/org/terasology/MapWorldProvider.java | 2 +- .../java/org/terasology/testUtil/WorldProviderCoreStub.java | 2 +- .../subsystem/headless/renderer/HeadlessWorldRenderer.java | 4 ++-- .../terasology/rendering/world/ChunkMeshUpdateManager.java | 2 +- .../org/terasology/rendering/world/RenderableWorldImpl.java | 2 +- .../world/internal/AbstractWorldProviderDecorator.java | 2 +- .../java/org/terasology/world/internal/WorldProviderCore.java | 2 +- .../org/terasology/world/internal/WorldProviderCoreImpl.java | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java index d569e45729d..a22e1567ef0 100644 --- a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java +++ b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java @@ -143,7 +143,7 @@ public WorldInfo getWorldInfo() { } @Override - public ChunkViewCore getLocalView(Vector3i chunkPos) { + public ChunkViewCore getLocalView(Vector3ic chunkPos) { return null; } diff --git a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java index 16830ab4adb..8a11a8e6573 100644 --- a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java +++ b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java @@ -85,7 +85,7 @@ public void unregisterListener(WorldChangeListener listener) { } @Override - public ChunkViewCore getLocalView(Vector3i chunkPos) { + public ChunkViewCore getLocalView(Vector3ic chunkPos) { return null; //To change body of implemented methods use File | Settings | File Templates. } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java index 3ba72fa9d73..c7f17dfa46f 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java @@ -212,7 +212,7 @@ public boolean updateChunksInProximity(boolean force) { chunksInProximity.clear(); for (Vector3i chunkPosition : viewRegion) { RenderableChunk c = chunkProvider.getChunk(chunkPosition); - if (c != null && worldProvider.getLocalView(c.getPosition()) != null) { + if (c != null && worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())) != null) { chunksInProximity.add(c); } else { chunksCurrentlyPending = true; @@ -235,7 +235,7 @@ public boolean updateChunksInProximity(boolean force) { // add for (Vector3i chunkPosition : viewRegion) { RenderableChunk c = chunkProvider.getChunk(chunkPosition); - if (c != null && worldProvider.getLocalView(c.getPosition()) != null) { + if (c != null && worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())) != null) { chunksInProximity.add(c); } else { chunksCurrentlyPending = true; diff --git a/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java b/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java index 27f4363e6dc..b3260c34c6f 100644 --- a/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java +++ b/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java @@ -162,7 +162,7 @@ public boolean isTerminateSignal() { @Override public void run() { ChunkMesh newMesh; - ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); + ChunkView chunkView = worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())); if (chunkView != null) { /* * Important set dirty flag first, so that a concurrent modification of the chunk in the mean time we diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index 1bccf7ef7b6..1ebce6d80c4 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -147,7 +147,7 @@ public boolean pregenerateChunks() { if (chunk == null) { pregenerationIsComplete = false; } else if (chunk.isDirty()) { - localView = worldProvider.getLocalView(JomlUtil.from(chunkCoordinates)); + localView = worldProvider.getLocalView(chunkCoordinates); if (localView == null) { continue; } diff --git a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java index 38a914bdb2f..4f5dcd5a805 100644 --- a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java +++ b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java @@ -75,7 +75,7 @@ public void unregisterListener(WorldChangeListener listener) { } @Override - public ChunkViewCore getLocalView(Vector3i chunkPos) { + public ChunkViewCore getLocalView(Vector3ic chunkPos) { return base.getLocalView(chunkPos); } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java index bd0aa3268bb..79a91089ccf 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java @@ -76,7 +76,7 @@ public interface WorldProviderCore { * @param chunkPos * @return A world view centered on the desired chunk, with the surrounding chunks present. */ - ChunkViewCore getLocalView(Vector3i chunkPos); + ChunkViewCore getLocalView(Vector3ic chunkPos); /** * @param chunk diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index 934040f54d7..ae5f3a56800 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -148,8 +148,8 @@ public void unregisterListener(WorldChangeListener listener) { } @Override - public ChunkViewCore getLocalView(Vector3i chunkPos) { - return chunkProvider.getLocalView(chunkPos); + public ChunkViewCore getLocalView(Vector3ic chunkPos) { + return chunkProvider.getLocalView(JomlUtil.from(chunkPos)); } @Override From 3537a9c366390ad9b4fd3219c9da183f777c3c60 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sun, 10 Jan 2021 17:17:56 +0100 Subject: [PATCH 104/259] chore(world): remove unused AbstractChunkView.java (#4390) --- .../world/propagation/AbstractChunkView.java | 85 ------------------- 1 file changed, 85 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java diff --git a/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java b/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java deleted file mode 100644 index ddf23289a29..00000000000 --- a/engine/src/main/java/org/terasology/world/propagation/AbstractChunkView.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.world.propagation; - -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; -import org.terasology.world.block.Block; -import org.terasology.world.internal.ChunkViewCore; - -/** - * Intermediate abstract class for the propagater world view that handles common functionality. - *

- * Only provides a view for a single chunk - * - * @see AbstractFullWorldView - */ -public abstract class AbstractChunkView implements PropagatorWorldView { - - private ChunkViewCore chunkView; - - public AbstractChunkView(ChunkViewCore chunkView) { - this.chunkView = chunkView; - } - - @Override - public byte getValueAt(Vector3i pos) { - if (isInBounds(pos)) { - return getValueAt(chunkView, pos); - } - return UNAVAILABLE; - } - - /** - * Equivalent to {@link #getValueAt(Vector3i)} - * - * @param view The chunk the position is within - * @param pos The position of to get the value at - * @return The value of the propagating data at the given position - */ - protected abstract byte getValueAt(ChunkViewCore view, Vector3i pos); - - @Override - public void setValueAt(Vector3i pos, byte value) { - setValueAt(chunkView, pos, value); - } - - /** - * Equivalent to {@link #setValueAt(Vector3i, byte)} - * - * @param view The chunk the position is in - * @param pos The position to set the value at - * @param value The value to set the position to - */ - protected abstract void setValueAt(ChunkViewCore view, Vector3i pos, byte value); - - @Override - public Block getBlockAt(Vector3i pos) { - if (isInBounds(pos)) { - return chunkView.getBlock(JomlUtil.from(pos)); - } - return null; - } - - /** - * Checks if the position is within the boundaries of the chunk represented by this class - * - * @param pos The position to check, in world coordinates - */ - public boolean isInBounds(Vector3i pos) { - return chunkView.getWorldRegion().contains(JomlUtil.from(pos)); - } -} From ba252ab78529aab1e33b7c4d6d86cdebe792814d Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sun, 10 Jan 2021 19:34:22 +0100 Subject: [PATCH 105/259] feat(JOML): add JOML API for `world.propagation.*` (partial) (#4384) * feat(JOML): add JOML API for `world.propagation.*` (partial migration) * test(JOML): migrate tests for `world.propagation.*` * chore(joml): replace ChunkConstants with Chunks * chore: apply auto-formatting to BulkLightPropagationTest --- .../propagation/StubPropagatorWorldView.java | 43 ++++--- .../propagation/BulkLightPropagationTest.java | 108 +++++++++--------- .../BulkSunlightPropagationTest.java | 64 +++++------ .../java/org/terasology/math/JomlUtil.java | 4 + .../propagation/AbstractFullWorldView.java | 35 +++--- .../world/propagation/LocalChunkView.java | 32 +++--- .../world/propagation/PropagationRules.java | 32 +++++- .../propagation/PropagatorWorldView.java | 38 +++++- .../world/propagation/SingleChunkView.java | 14 +-- .../light/InternalLightProcessor.java | 20 ++-- .../light/LightPropagationRules.java | 17 +-- .../propagation/light/LightWorldView.java | 11 +- .../light/SunlightPropagationRules.java | 21 ++-- .../light/SunlightRegenPropagationRules.java | 23 ++-- .../light/SunlightRegenWorldView.java | 11 +- .../propagation/light/SunlightWorldView.java | 11 +- 16 files changed, 285 insertions(+), 199 deletions(-) diff --git a/engine-tests/src/main/java/org/terasology/world/propagation/StubPropagatorWorldView.java b/engine-tests/src/main/java/org/terasology/world/propagation/StubPropagatorWorldView.java index e11f66d4de3..37e0b5b5c25 100644 --- a/engine-tests/src/main/java/org/terasology/world/propagation/StubPropagatorWorldView.java +++ b/engine-tests/src/main/java/org/terasology/world/propagation/StubPropagatorWorldView.java @@ -18,49 +18,64 @@ import com.google.common.collect.Maps; import gnu.trove.map.TObjectByteMap; import gnu.trove.map.hash.TObjectByteHashMap; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import java.util.Map; /** */ public class StubPropagatorWorldView implements PropagatorWorldView { - private TObjectByteMap lightData = new TObjectByteHashMap<>(); - private Map blockData = Maps.newHashMap(); - private Region3i relevantRegion; + private TObjectByteMap lightData = new TObjectByteHashMap<>(); + private Map blockData = Maps.newHashMap(); + private BlockRegionc relevantRegion; private Block defaultBlock; + @Deprecated public StubPropagatorWorldView(Region3i relevantRegion, Block defaultBlock) { - this.relevantRegion = relevantRegion; + this(JomlUtil.from(relevantRegion), defaultBlock); + } + + public StubPropagatorWorldView(BlockRegionc relevantRegion, Block defaultBlock) { + this.relevantRegion = new BlockRegion(relevantRegion); this.defaultBlock = defaultBlock; } - public StubPropagatorWorldView(Region3i relevantRegion, Block defaultBlock, Map blockData) { + @Deprecated + public StubPropagatorWorldView(Region3i relevantRegion, Block defaultBlock, Map blockData) { + this(JomlUtil.from(relevantRegion), defaultBlock, JomlUtil.toBlockMap(blockData)); + } + + public StubPropagatorWorldView(BlockRegionc relevantRegion, Block defaultBlock, Map blockData) { this(relevantRegion, defaultBlock); this.blockData = blockData; } + @Override - public byte getValueAt(Vector3i pos) { - if (!relevantRegion.encompasses(pos)) { + public byte getValueAt(Vector3ic pos) { + if (!relevantRegion.contains(pos)) { return UNAVAILABLE; } return lightData.get(pos); } @Override - public void setValueAt(Vector3i pos, byte value) { - if (!relevantRegion.encompasses(pos)) { + public void setValueAt(Vector3ic pos, byte value) { + if (!relevantRegion.contains(pos)) { throw new IllegalArgumentException("Position out of bounds: " + pos); } lightData.put(new Vector3i(pos), value); } @Override - public Block getBlockAt(Vector3i pos) { - if (!relevantRegion.encompasses(pos)) { + public Block getBlockAt(Vector3ic pos) { + if (!relevantRegion.contains(pos)) { throw new IllegalArgumentException("Position out of bounds: " + pos); } @@ -71,8 +86,8 @@ public Block getBlockAt(Vector3i pos) { return result; } - public void setBlockAt(Vector3i pos, Block block) { - if (!relevantRegion.encompasses(pos)) { + public void setBlockAt(Vector3ic pos, Block block) { + if (!relevantRegion.contains(pos)) { throw new IllegalArgumentException("Position out of bounds: " + pos); } diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BulkLightPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BulkLightPropagationTest.java index b2a53a79269..6082f90f358 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BulkLightPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BulkLightPropagationTest.java @@ -15,19 +15,18 @@ */ package org.terasology.world.propagation; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; -import org.terasology.math.Diamond3iIterator; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.Diamond3iIterable; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockUri; import org.terasology.world.block.family.SymmetricFamily; import org.terasology.world.block.internal.BlockManagerImpl; @@ -35,14 +34,14 @@ import org.terasology.world.block.loader.BlockFamilyDefinitionData; import org.terasology.world.block.shapes.BlockShape; import org.terasology.world.block.tiles.NullWorldAtlas; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.propagation.light.LightPropagationRules; import static org.junit.jupiter.api.Assertions.assertEquals; public class BulkLightPropagationTest extends TerasologyTestingEnvironment { - private static final Vector3ic ZERO_VECTOR = new org.joml.Vector3i(); + private static final Vector3ic ZERO_VECTOR = new Vector3i(); private BlockManagerImpl blockManager; private Block air; @@ -53,8 +52,8 @@ public class BulkLightPropagationTest extends TerasologyTestingEnvironment { private Block solidMediumLight; private LightPropagationRules lightRules; - private Region3i testingRegion = Region3i.createFromMinMax(new Vector3i(-ChunkConstants.SIZE_X, -ChunkConstants.SIZE_Y, -ChunkConstants.SIZE_Z), - new Vector3i(2 * ChunkConstants.SIZE_X, 2 * ChunkConstants.SIZE_Y, 2 * ChunkConstants.SIZE_Z)); + private BlockRegion testingRegion = new BlockRegion(-Chunks.SIZE_X, -Chunks.SIZE_Y, -Chunks.SIZE_Z, + 2 * Chunks.SIZE_X, 2 * Chunks.SIZE_Y, 2 * Chunks.SIZE_Z); @BeforeEach public void setup() throws Exception { @@ -66,7 +65,7 @@ public void setup() throws Exception { BlockFamilyDefinitionData fullLightData = new BlockFamilyDefinitionData(); fullLightData.getBaseSection().setDisplayName("Torch"); fullLightData.getBaseSection().setShape(assetManager.getAsset("engine:cube", BlockShape.class).get()); - fullLightData.getBaseSection().setLuminance(ChunkConstants.MAX_LIGHT); + fullLightData.getBaseSection().setLuminance(Chunks.MAX_LIGHT); fullLightData.getBaseSection().setTranslucent(true); fullLightData.setBlockFamily(SymmetricFamily.class); assetManager.loadAsset(new ResourceUrn("engine:torch"), fullLightData, BlockFamilyDefinition.class); @@ -104,7 +103,8 @@ public void setup() throws Exception { solidMediumLightData.getBaseSection().setTranslucent(false); solidMediumLightData.getBaseSection().setLuminance((byte) 5); solidMediumLightData.setBlockFamily(SymmetricFamily.class); - assetManager.loadAsset(new ResourceUrn("engine:solidMediumLight"), solidMediumLightData, BlockFamilyDefinition.class); + assetManager.loadAsset(new ResourceUrn("engine:solidMediumLight"), solidMediumLightData, + BlockFamilyDefinition.class); solidMediumLight = blockManager.getBlock(new BlockUri(new ResourceUrn("engine:solidMediumLight"))); air = blockManager.getBlock(BlockManager.AIR_ID); @@ -113,16 +113,16 @@ public void setup() throws Exception { @Test public void testAddLightInVacuum() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - worldView.setBlockAt(Vector3i.zero(), fullLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight)); - assertEquals(fullLight.getLuminance(), worldView.getValueAt(Vector3i.zero())); + assertEquals(fullLight.getLuminance(), worldView.getValueAt(new Vector3i(0, 0, 0))); assertEquals(fullLight.getLuminance() - 1, worldView.getValueAt(new Vector3i(0, 1, 0))); assertEquals(fullLight.getLuminance() - 14, worldView.getValueAt(new Vector3i(0, 14, 0))); for (int i = 1; i < fullLight.getLuminance(); ++i) { - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(fullLight.getLuminance() - i, worldView.getValueAt(pos)); } } @@ -131,16 +131,16 @@ public void testAddLightInVacuum() { @Test public void testRemoveLightInVacuum() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - worldView.setBlockAt(Vector3i.zero(), fullLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight)); - worldView.setBlockAt(Vector3i.zero(), air); + worldView.setBlockAt(new Vector3i(0, 0, 0), air); propagator.process(new BlockChange(ZERO_VECTOR, fullLight, air)); - assertEquals(0, worldView.getValueAt(Vector3i.zero())); + assertEquals(0, worldView.getValueAt(new Vector3i(0, 0, 0))); for (int i = 1; i < fullLight.getLuminance(); ++i) { - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(0, worldView.getValueAt(pos)); } } @@ -149,17 +149,17 @@ public void testRemoveLightInVacuum() { @Test public void testReduceLight() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - worldView.setBlockAt(Vector3i.zero(), fullLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight)); - worldView.setBlockAt(Vector3i.zero(), weakLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), weakLight); propagator.process(new BlockChange(ZERO_VECTOR, fullLight, weakLight)); - assertEquals(weakLight.getLuminance(), worldView.getValueAt(Vector3i.zero())); + assertEquals(weakLight.getLuminance(), worldView.getValueAt(new Vector3i(0, 0, 0))); for (int i = 1; i < 15; ++i) { byte expectedLuminance = (byte) Math.max(0, weakLight.getLuminance() - i); - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } @@ -169,13 +169,13 @@ public void testReduceLight() { public void testAddOverlappingLights() { Vector3i lightPos = new Vector3i(5, 0, 0); - StubPropagatorWorldView worldView = new StubPropagatorWorldView(ChunkConstants.CHUNK_REGION, air); - worldView.setBlockAt(Vector3i.zero(), fullLight); + StubPropagatorWorldView worldView = new StubPropagatorWorldView(Chunks.CHUNK_REGION, air); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); worldView.setBlockAt(lightPos, fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight), new BlockChange(JomlUtil.from(lightPos), air, fullLight)); + propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight), new BlockChange(lightPos, air, fullLight)); - assertEquals(fullLight.getLuminance(), worldView.getValueAt(Vector3i.zero())); + assertEquals(fullLight.getLuminance(), worldView.getValueAt(new Vector3i(0, 0, 0))); assertEquals(fullLight.getLuminance() - 1, worldView.getValueAt(new Vector3i(1, 0, 0))); assertEquals(fullLight.getLuminance() - 2, worldView.getValueAt(new Vector3i(2, 0, 0))); assertEquals(fullLight.getLuminance() - 2, worldView.getValueAt(new Vector3i(3, 0, 0))); @@ -188,17 +188,17 @@ public void testRemoveOverlappingLight() { Vector3i lightPos = new Vector3i(5, 0, 0); StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - worldView.setBlockAt(Vector3i.zero(), fullLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); worldView.setBlockAt(lightPos, fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight), new BlockChange(JomlUtil.from(lightPos), air, fullLight)); + propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight), new BlockChange(lightPos, air, fullLight)); worldView.setBlockAt(lightPos, air); - propagator.process(new BlockChange(JomlUtil.from(lightPos), fullLight, air)); + propagator.process(new BlockChange(lightPos, fullLight, air)); for (int i = 0; i < 16; ++i) { byte expectedLuminance = (byte) Math.max(0, fullLight.getLuminance() - i); - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } @@ -209,17 +209,17 @@ public void testRemoveLightOverlappingAtEdge() { Vector3i lightPos = new Vector3i(2, 0, 0); StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - worldView.setBlockAt(Vector3i.zero(), weakLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), weakLight); worldView.setBlockAt(lightPos, weakLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(ZERO_VECTOR, air, weakLight), new BlockChange(JomlUtil.from(lightPos), air, weakLight)); + propagator.process(new BlockChange(ZERO_VECTOR, air, weakLight), new BlockChange(lightPos, air, weakLight)); worldView.setBlockAt(lightPos, air); - propagator.process(new BlockChange(JomlUtil.from(lightPos), weakLight, air)); + propagator.process(new BlockChange(lightPos, weakLight, air)); for (int i = 0; i < weakLight.getLuminance() + 1; ++i) { byte expectedLuminance = (byte) Math.max(0, weakLight.getLuminance() - i); - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } @@ -230,14 +230,14 @@ public void testAddLightInLight() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); worldView.setBlockAt(new Vector3i(2, 0, 0), mediumLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(2, 0, 0)), air, mediumLight)); + propagator.process(new BlockChange(new Vector3i(2, 0, 0), air, mediumLight)); - worldView.setBlockAt(Vector3i.zero(), fullLight); + worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight)); for (int i = 0; i < fullLight.getLuminance() + 1; ++i) { byte expectedLuminance = (byte) Math.max(0, fullLight.getLuminance() - i); - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } @@ -249,11 +249,12 @@ public void testAddAdjacentLights() { worldView.setBlockAt(new Vector3i(1, 0, 0), mediumLight); worldView.setBlockAt(new Vector3i(0, 0, 0), mediumLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), air, mediumLight), new BlockChange(ZERO_VECTOR, air, mediumLight)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), air, mediumLight), new BlockChange(ZERO_VECTOR, air + , mediumLight)); for (int i = 0; i < fullLight.getLuminance() + 1; ++i) { - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { - int dist = Math.min(Vector3i.zero().gridDistance(pos), new Vector3i(1, 0, 0).gridDistance(pos)); + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { + long dist = Math.min(new Vector3i(0, 0, 0).gridDistance(pos), new Vector3i(1, 0, 0).gridDistance(pos)); byte expectedLuminance = (byte) Math.max(mediumLight.getLuminance() - dist, 0); assertEquals(expectedLuminance, worldView.getValueAt(pos)); } @@ -268,7 +269,7 @@ public void testAddWeakLightNextToStrongLight() { propagator.process(new BlockChange(ZERO_VECTOR, air, fullLight)); worldView.setBlockAt(new Vector3i(1, 0, 0), weakLight); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), air, weakLight)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), air, weakLight)); assertEquals(14, worldView.getValueAt(new Vector3i(1, 0, 0))); } @@ -278,15 +279,17 @@ public void testRemoveAdjacentLights() { worldView.setBlockAt(new Vector3i(1, 0, 0), mediumLight); worldView.setBlockAt(new Vector3i(0, 0, 0), mediumLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), air, mediumLight), new BlockChange(ZERO_VECTOR, air, mediumLight)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), air, mediumLight), new BlockChange(ZERO_VECTOR, air + , mediumLight)); worldView.setBlockAt(new Vector3i(1, 0, 0), air); worldView.setBlockAt(new Vector3i(0, 0, 0), air); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), mediumLight, air), new BlockChange(ZERO_VECTOR, mediumLight, air)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), mediumLight, air), new BlockChange(ZERO_VECTOR, + mediumLight, air)); for (int i = 0; i < fullLight.getLuminance() + 1; ++i) { byte expectedLuminance = (byte) 0; - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } @@ -294,13 +297,13 @@ public void testRemoveAdjacentLights() { @Test public void testAddSolidBlocksLight() { - StubPropagatorWorldView worldView = new StubPropagatorWorldView(ChunkConstants.CHUNK_REGION, air); + StubPropagatorWorldView worldView = new StubPropagatorWorldView(Chunks.CHUNK_REGION, air); worldView.setBlockAt(new Vector3i(0, 0, 0), mediumLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); propagator.process(new BlockChange(ZERO_VECTOR, air, mediumLight)); worldView.setBlockAt(new Vector3i(1, 0, 0), solid); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), air, solid)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), air, solid)); assertEquals(0, worldView.getValueAt(new Vector3i(1, 0, 0))); assertEquals(1, worldView.getValueAt(new Vector3i(2, 0, 0))); @@ -309,8 +312,8 @@ public void testAddSolidBlocksLight() { @Test public void testRemoveSolidAllowsLight() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - for (Vector3i pos : Region3i.createFromCenterExtents(new Vector3i(1, 0, 0), new Vector3i(0, 30, 30))) { - worldView.setBlockAt(pos, solid); + for (Vector3ic pos : new BlockRegion(1, 0, 0).expand(0, 30, 30)) { + worldView.setBlockAt(new Vector3i(pos), solid); } worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); @@ -319,7 +322,7 @@ public void testRemoveSolidAllowsLight() { assertEquals(0, worldView.getValueAt(new Vector3i(1, 0, 0))); worldView.setBlockAt(new Vector3i(1, 0, 0), air); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), solid, air)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), solid, air)); assertEquals(14, worldView.getValueAt(new Vector3i(1, 0, 0))); assertEquals(13, worldView.getValueAt(new Vector3i(2, 0, 0))); @@ -328,8 +331,8 @@ public void testRemoveSolidAllowsLight() { @Test public void testRemoveSolidAndLight() { StubPropagatorWorldView worldView = new StubPropagatorWorldView(testingRegion, air); - for (Vector3i pos : Region3i.createFromCenterExtents(new Vector3i(1, 0, 0), new Vector3i(0, 30, 30))) { - worldView.setBlockAt(pos, solid); + for (Vector3ic pos : new BlockRegion(1, 0, 0).expand(0, 30, 30)) { + worldView.setBlockAt(new Vector3i(pos), solid); } worldView.setBlockAt(new Vector3i(0, 0, 0), fullLight); BatchPropagator propagator = new StandardBatchPropagator(lightRules, worldView); @@ -339,11 +342,12 @@ public void testRemoveSolidAndLight() { worldView.setBlockAt(new Vector3i(1, 0, 0), air); worldView.setBlockAt(new Vector3i(0, 0, 0), air); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(1, 0, 0)), solid, air), new BlockChange(ZERO_VECTOR, fullLight, air)); + propagator.process(new BlockChange(new Vector3i(1, 0, 0), solid, air), new BlockChange(ZERO_VECTOR, fullLight + , air)); for (int i = 0; i < fullLight.getLuminance() + 1; ++i) { byte expectedLuminance = (byte) 0; - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(Vector3i.zero(), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(0, 0, 0), i).build()) { assertEquals(expectedLuminance, worldView.getValueAt(pos)); } } diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BulkSunlightPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BulkSunlightPropagationTest.java index 15679d0b898..f4ce541828b 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BulkSunlightPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BulkSunlightPropagationTest.java @@ -16,17 +16,17 @@ package org.terasology.world.propagation; import com.google.common.collect.Maps; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockUri; import org.terasology.world.block.family.SymmetricFamily; import org.terasology.world.block.internal.BlockManagerImpl; @@ -34,7 +34,7 @@ import org.terasology.world.block.loader.BlockFamilyDefinitionData; import org.terasology.world.block.shapes.BlockShape; import org.terasology.world.block.tiles.NullWorldAtlas; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.propagation.light.SunlightPropagationRules; import org.terasology.world.propagation.light.SunlightRegenPropagationRules; @@ -76,9 +76,9 @@ public void setup() throws Exception { air = blockManager.getBlock(BlockManager.AIR_ID); - Map blockData = Maps.newHashMap(); - regenWorldView = new StubPropagatorWorldView(ChunkConstants.CHUNK_REGION, air, blockData); - lightWorldView = new StubPropagatorWorldView(ChunkConstants.CHUNK_REGION, air, blockData); + Map blockData = Maps.newHashMap(); + regenWorldView = new StubPropagatorWorldView(Chunks.CHUNK_REGION, air, blockData); + lightWorldView = new StubPropagatorWorldView(Chunks.CHUNK_REGION, air, blockData); lightRules = new SunlightPropagationRules(regenWorldView); sunlightPropagator = new StandardBatchPropagator(lightRules, lightWorldView); @@ -89,53 +89,53 @@ public void setup() throws Exception { @Test public void testAllowSunlightVertical() { - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 16, 0), new Vector3i(ChunkConstants.SIZE_X - 1, ChunkConstants.SIZE_Y - 1, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setValueAt(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); - lightWorldView.setValueAt(pos, ChunkConstants.MAX_SUNLIGHT); + for (Vector3ic pos : new BlockRegion(0, 16, 0).union(Chunks.SIZE_X - 1, Chunks.SIZE_Y - 1, Chunks.SIZE_Z - 1)) { + regenWorldView.setValueAt(pos, Chunks.MAX_SUNLIGHT_REGEN); + lightWorldView.setValueAt(pos, Chunks.MAX_SUNLIGHT); } - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 15, 0), new Vector3i(ChunkConstants.SIZE_X - 1, 15, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setBlockAt(pos, solid); + for (Vector3ic pos : new BlockRegion(0, 15, 0).union(Chunks.SIZE_X - 1, 15, Chunks.SIZE_Z - 1)) { + regenWorldView.setBlockAt(new Vector3i(pos), solid); } - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X - 1, 14, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setValueAt(pos, (byte) (14 - pos.y)); + for (Vector3ic pos : new BlockRegion(0, 0, 0).union(Chunks.SIZE_X - 1, 14, Chunks.SIZE_Z - 1)) { + regenWorldView.setValueAt(pos, (byte) (14 - pos.y())); } regenWorldView.setBlockAt(new Vector3i(16, 15, 16), air); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), solid, air)); - sunlightPropagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), solid, air)); + propagator.process(new BlockChange(new Vector3i(16, 15, 16), solid, air)); + sunlightPropagator.process(new BlockChange(new Vector3i(16, 15, 16), solid, air)); for (int y = 0; y < 16; y++) { - assertEquals(ChunkConstants.MAX_SUNLIGHT_REGEN, regenWorldView.getValueAt(new Vector3i(16, y, 16)), "Incorrect value at " + y); - assertEquals(ChunkConstants.MAX_SUNLIGHT, lightWorldView.getValueAt(new Vector3i(16, y, 16))); + assertEquals(Chunks.MAX_SUNLIGHT_REGEN, regenWorldView.getValueAt(new Vector3i(16, y, 16)), "Incorrect value at " + y); + assertEquals(Chunks.MAX_SUNLIGHT, lightWorldView.getValueAt(new Vector3i(16, y, 16))); } for (int y = 0; y < 15; y++) { - assertEquals(ChunkConstants.MAX_SUNLIGHT - 1, lightWorldView.getValueAt(new Vector3i(15, y, 16))); + assertEquals(Chunks.MAX_SUNLIGHT - 1, lightWorldView.getValueAt(new Vector3i(15, y, 16))); } } @Test public void testStopSunlightVertical() { - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 16, 0), new Vector3i(ChunkConstants.SIZE_X - 1, ChunkConstants.SIZE_Y - 1, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setValueAt(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); - lightWorldView.setValueAt(pos, ChunkConstants.MAX_SUNLIGHT); + for (Vector3ic pos : new BlockRegion(0, 16, 0).union(Chunks.SIZE_X - 1, Chunks.SIZE_Y - 1, Chunks.SIZE_Z - 1)) { + regenWorldView.setValueAt(pos, Chunks.MAX_SUNLIGHT_REGEN); + lightWorldView.setValueAt(pos, Chunks.MAX_SUNLIGHT); } - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 15, 0), new Vector3i(ChunkConstants.SIZE_X - 1, 15, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setBlockAt(pos, solid); + for (Vector3ic pos : new BlockRegion(0, 15, 0).union(Chunks.SIZE_X - 1, 15, Chunks.SIZE_Z - 1)) { + regenWorldView.setBlockAt(new Vector3i(pos), solid); } - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X - 1, 14, ChunkConstants.SIZE_Z - 1))) { - regenWorldView.setValueAt(pos, (byte) (14 - pos.y)); + for (Vector3ic pos : new BlockRegion(0, 0, 0).union(Chunks.SIZE_X - 1, 14, Chunks.SIZE_Z - 1)) { + regenWorldView.setValueAt(pos, (byte) (14 - pos.y())); } regenWorldView.setBlockAt(new Vector3i(16, 15, 16), air); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), solid, air)); - sunlightPropagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), solid, air)); + propagator.process(new BlockChange(new Vector3i(16, 15, 16), solid, air)); + sunlightPropagator.process(new BlockChange(new Vector3i(16, 15, 16), solid, air)); regenWorldView.setBlockAt(new Vector3i(16, 15, 16), solid); - propagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), air, solid)); - sunlightPropagator.process(new BlockChange(JomlUtil.from(new Vector3i(16, 15, 16)), air, solid)); + propagator.process(new BlockChange(new Vector3i(16, 15, 16), air, solid)); + sunlightPropagator.process(new BlockChange(new Vector3i(16, 15, 16), air, solid)); - for (Vector3i pos : Region3i.createBounded(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X - 1, 15, ChunkConstants.SIZE_Z - 1))) { - assertEquals(Math.max(0, 14 - pos.y), regenWorldView.getValueAt(pos), "Incorrect value at " + pos); + for (Vector3ic pos : new BlockRegion(0, 0, 0).union(Chunks.SIZE_X - 1, 15, Chunks.SIZE_Z - 1)) { + assertEquals(Math.max(0, 14 - pos.y()), regenWorldView.getValueAt(pos), "Incorrect value at " + pos); assertEquals(0, lightWorldView.getValueAt(pos), "Incorrect value at " + pos); } } diff --git a/engine/src/main/java/org/terasology/math/JomlUtil.java b/engine/src/main/java/org/terasology/math/JomlUtil.java index 91004e5c964..4df4a000451 100644 --- a/engine/src/main/java/org/terasology/math/JomlUtil.java +++ b/engine/src/main/java/org/terasology/math/JomlUtil.java @@ -246,4 +246,8 @@ public static Rectanglef rectanglefFromMinAndSize(float minX, float minY, float public static Map blockMap(Map maps) { return maps.entrySet().stream().collect(Collectors.toMap(k -> JomlUtil.from(k.getKey()), Map.Entry::getValue)); } + + public static Map toBlockMap(Map maps) { + return maps.entrySet().stream().collect(Collectors.toMap(k -> JomlUtil.from(k.getKey()), Map.Entry::getValue)); + } } diff --git a/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java b/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java index afb75940366..b1871246913 100644 --- a/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java @@ -15,11 +15,14 @@ */ package org.terasology.world.propagation; -import org.terasology.math.ChunkMath; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.CoreChunk; import org.terasology.world.chunks.LitChunk; @@ -40,16 +43,15 @@ public AbstractFullWorldView(ChunkProvider chunkProvider) { * @param pos The position in the world * @return The chunk for that position */ - private Chunk getChunk(Vector3i pos) { - - return chunkProvider.getChunk(ChunkMath.calcChunkPos(pos)); + private Chunk getChunk(Vector3ic pos) { + return chunkProvider.getChunk(JomlUtil.from(Chunks.toChunkPos(pos, new Vector3i()))); } @Override - public byte getValueAt(Vector3i pos) { + public byte getValueAt(Vector3ic pos) { LitChunk chunk = getChunk(pos); if (chunk != null) { - return getValueAt(chunk, ChunkMath.calcRelativeBlockPos(pos.x, pos.y, pos.z)); + return getValueAt(chunk, Chunks.toRelative(pos, new Vector3i())); } return UNAVAILABLE; } @@ -61,13 +63,14 @@ public byte getValueAt(Vector3i pos) { * @param pos The internal position of the chunk to get the value from * @return The relevant value for this view */ - protected abstract byte getValueAt(LitChunk chunk, Vector3i pos); + protected abstract byte getValueAt(LitChunk chunk, Vector3ic pos); @Override - public void setValueAt(Vector3i pos, byte value) { - setValueAt(getChunk(pos), ChunkMath.calcRelativeBlockPos(pos.x, pos.y, pos.z), value); - for (Vector3i affectedChunkPos : ChunkMath.getChunkRegionAroundWorldPos(pos, 1)) { - Chunk dirtiedChunk = chunkProvider.getChunk(affectedChunkPos); + public void setValueAt(Vector3ic pos, byte value) { + setValueAt(getChunk(pos), Chunks.toRelative(pos, new Vector3i()), value); + BlockRegion chunkRegion = new BlockRegion(pos).expand(1, 1, 1); + for (Vector3ic affectedChunkPos : Chunks.toChunkRegion(chunkRegion, chunkRegion)) { + Chunk dirtiedChunk = chunkProvider.getChunk(JomlUtil.from(affectedChunkPos)); if (dirtiedChunk != null) { dirtiedChunk.setDirty(true); } @@ -81,13 +84,13 @@ public void setValueAt(Vector3i pos, byte value) { * @param pos The internal position of the chunk to set the value of * @param value The new value */ - protected abstract void setValueAt(LitChunk chunk, Vector3i pos, byte value); + protected abstract void setValueAt(LitChunk chunk, Vector3ic pos, byte value); @Override - public Block getBlockAt(Vector3i pos) { - CoreChunk chunk = chunkProvider.getChunk(ChunkMath.calcChunkPos(pos)); + public Block getBlockAt(Vector3ic pos) { + CoreChunk chunk = chunkProvider.getChunk(JomlUtil.from(Chunks.toChunkPos(pos, new Vector3i()))); if (chunk != null) { - return chunk.getBlock(ChunkMath.calcRelativeBlockPos(pos)); + return chunk.getBlock(Chunks.toRelative(pos, new Vector3i())); } return null; } diff --git a/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java b/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java index 7fde7cc0dc1..99e6a2b2858 100644 --- a/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java +++ b/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java @@ -2,29 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.math.ChunkMath; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; import org.terasology.world.block.Block; import org.terasology.world.chunks.Chunk; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; /** * Provides a simple view over some chunks using a propagation rule. */ public class LocalChunkView implements PropagatorWorldView { - private static final Logger logger = LoggerFactory.getLogger(LocalChunkView.class); private PropagationRules rules; private Chunk[] chunks; - private final Vector3i topLeft; + private final org.joml.Vector3i topLeft; public LocalChunkView(Chunk[] chunks, PropagationRules rules) { this.chunks = chunks; this.rules = rules; - topLeft = chunks[0].getPosition(); + topLeft = chunks[0].getPosition(new org.joml.Vector3i()); } /** @@ -33,39 +29,39 @@ public LocalChunkView(Chunk[] chunks, PropagationRules rules) { * @param blockPos The position of the block in world coordinates * @return The index of the chunk in the array */ - private int chunkIndexOf(Vector3i blockPos) { - return ChunkMath.calcChunkPos(blockPos.x, ChunkConstants.POWER_X) - topLeft.x - + 3 * (ChunkMath.calcChunkPos(blockPos.y, ChunkConstants.POWER_Y) - topLeft.y - + 3 * (ChunkMath.calcChunkPos(blockPos.z, ChunkConstants.POWER_Z) - topLeft.z)); + private int chunkIndexOf(Vector3ic blockPos) { + return Chunks.toChunkPos(blockPos.x(), Chunks.POWER_X) - topLeft.x + + 3 * (Chunks.toChunkPos(blockPos.y(), Chunks.POWER_Y) - topLeft.y + + 3 * (Chunks.toChunkPos(blockPos.z(), Chunks.POWER_Z) - topLeft.z)); } @Override - public byte getValueAt(Vector3i pos) { + public byte getValueAt(Vector3ic pos) { int index = chunkIndexOf(pos); if (index < 0) { return UNAVAILABLE; } Chunk chunk = chunks[index]; if (chunk != null) { - return rules.getValue(chunk, ChunkMath.calcRelativeBlockPos(pos)); + return rules.getValue(chunk, Chunks.toRelative(pos, new org.joml.Vector3i())); } return UNAVAILABLE; } @Override - public void setValueAt(Vector3i pos, byte value) { + public void setValueAt(Vector3ic pos, byte value) { Chunk chunk = chunks[chunkIndexOf(pos)]; if (chunk != null) { - rules.setValue(chunk, ChunkMath.calcRelativeBlockPos(pos), value); + rules.setValue(chunk, Chunks.toRelative(pos, new org.joml.Vector3i()), value); } } @Override - public Block getBlockAt(Vector3i pos) { + public Block getBlockAt(Vector3ic pos) { int index = chunkIndexOf(pos); Chunk chunk = chunks[index]; if (chunk != null) { - return chunk.getBlock(ChunkMath.calcRelativeBlockPos(pos)); + return chunk.getBlock(Chunks.toRelative(pos, new org.joml.Vector3i())); } return null; } diff --git a/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java index cedee83f0f8..57912413ecc 100644 --- a/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java @@ -15,11 +15,15 @@ */ package org.terasology.world.propagation; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.chunks.LitChunk; +import javax.swing.JOptionPane; + /** * Rules to drive value propagation. */ @@ -31,7 +35,15 @@ public interface PropagationRules { * @param pos The position of the block being checked * @return The constant value of this block */ - byte getFixedValue(Block block, Vector3i pos); + byte getFixedValue(Block block, Vector3ic pos); + + /** + * @deprecated use {@link #getFixedValue(Block, Vector3ic)} instead + */ + @Deprecated + default byte getFixedValue(Block block, Vector3i pos) { + return getFixedValue(block, JomlUtil.from(pos)); + } /** * Compare the how the propagation changes if you replace the block with a different one, on a given side @@ -84,7 +96,14 @@ public interface PropagationRules { * @param pos The position to get from * @return The value of the given position of a chunk */ - byte getValue(LitChunk chunk, Vector3i pos); + byte getValue(LitChunk chunk, Vector3ic pos); + + /** + * @deprecated use {@link #getValue(LitChunk, Vector3ic)} instead + */ + default byte getValue(LitChunk chunk, Vector3i pos) { + return getValue(chunk, JomlUtil.from(pos)); + } /** * See {@link #getValue(LitChunk, Vector3i)} @@ -104,5 +123,12 @@ public interface PropagationRules { * @param pos The position to set at * @param value The value to set to */ - void setValue(LitChunk chunk, Vector3i pos, byte value); + void setValue(LitChunk chunk, Vector3ic pos, byte value); + + /** + * @deprecated use {@link #setValue(LitChunk, Vector3ic, byte)} instead + */ + default void setValue(LitChunk chunk, Vector3i pos, byte value){ + setValue(chunk, JomlUtil.from(pos), value); + } } diff --git a/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java b/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java index 39a88ef065e..448a68f076a 100644 --- a/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java @@ -15,6 +15,8 @@ */ package org.terasology.world.propagation; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; @@ -27,17 +29,47 @@ public interface PropagatorWorldView { /** * @return The value of interest at pos, or {@link #UNAVAILABLE} if out of bounds + * + * @deprecated use {@link #getValueAt(Vector3ic)} instead */ - byte getValueAt(Vector3i pos); + @Deprecated + default byte getValueAt(Vector3i pos) { + return getValueAt(JomlUtil.from(pos)); + } + + /** + * @return The value of interest at pos, or {@link #UNAVAILABLE} if out of bounds + */ + byte getValueAt(Vector3ic pos); + + /** + * @param value A new value at pos. + * + * @deprecated use {@link #setValueAt(Vector3ic, byte)} instead + */ + @Deprecated + default void setValueAt(Vector3i pos, byte value) { + setValueAt(JomlUtil.from(pos), value); + }; /** * @param value A new value at pos. */ - void setValueAt(Vector3i pos, byte value); + void setValueAt(Vector3ic pos, byte value); + + /** + * @return The block at pos, or null if out of bounds + * + * @deprecated use {@link #getBlockAt(Vector3ic)} instead + */ + @Deprecated + default Block getBlockAt(Vector3i pos) { + return getBlockAt(JomlUtil.from(pos)); + }; /** * @return The block at pos, or null if out of bounds */ - Block getBlockAt(Vector3i pos); + Block getBlockAt(Vector3ic pos); } diff --git a/engine/src/main/java/org/terasology/world/propagation/SingleChunkView.java b/engine/src/main/java/org/terasology/world/propagation/SingleChunkView.java index 08c2efeaff3..9c164d65321 100644 --- a/engine/src/main/java/org/terasology/world/propagation/SingleChunkView.java +++ b/engine/src/main/java/org/terasology/world/propagation/SingleChunkView.java @@ -15,9 +15,9 @@ */ package org.terasology.world.propagation; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; /** @@ -34,21 +34,21 @@ public SingleChunkView(PropagationRules rules, LitChunk chunk) { } @Override - public byte getValueAt(Vector3i pos) { - if (ChunkConstants.CHUNK_REGION.encompasses(pos)) { + public byte getValueAt(Vector3ic pos) { + if (Chunks.CHUNK_REGION.contains(pos)) { return rules.getValue(chunk, pos); } return UNAVAILABLE; } @Override - public void setValueAt(Vector3i pos, byte value) { + public void setValueAt(Vector3ic pos, byte value) { rules.setValue(chunk, pos, value); } @Override - public Block getBlockAt(Vector3i pos) { - if (ChunkConstants.CHUNK_REGION.encompasses(pos)) { + public Block getBlockAt(Vector3ic pos) { + if (Chunks.CHUNK_REGION.contains(pos)) { return chunk.getBlock(pos); } return null; diff --git a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java index 4e7c6f644f4..758fbbb07fa 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java @@ -19,7 +19,7 @@ import org.terasology.math.Side; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.BatchPropagator; import org.terasology.world.propagation.PropagationRules; @@ -51,9 +51,9 @@ public static void generateInternalLighting(LitChunk chunk) { */ private static void populateLight(LitChunk chunk) { BatchPropagator lightPropagator = new StandardBatchPropagator(LIGHT_RULES, new SingleChunkView(LIGHT_RULES, chunk)); - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { - for (int y = 0; y < ChunkConstants.SIZE_Y; y++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { + for (int y = 0; y < Chunks.SIZE_Y; y++) { Block block = chunk.getBlock(x, y, z); if (block.getLuminance() > 0) { chunk.setLight(x, y, z, block.getLuminance()); @@ -74,10 +74,10 @@ private static void populateSunlight(LitChunk chunk) { PropagationRules sunlightRules = new SunlightPropagationRules(chunk); BatchPropagator lightPropagator = new StandardBatchPropagator(sunlightRules, new SingleChunkView(sunlightRules, chunk)); - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { /* Start at the bottom of the chunk and then move up until the max sunlight level */ - for (int y = 0; y < ChunkConstants.MAX_SUNLIGHT; y++) { + for (int y = 0; y < Chunks.MAX_SUNLIGHT; y++) { Vector3i pos = new Vector3i(x, y, z); Block block = chunk.getBlock(x, y, z); byte light = sunlightRules.getFixedValue(block, pos); @@ -97,10 +97,10 @@ private static void populateSunlight(LitChunk chunk) { * @param chunk The chunk to populate the regeneration values through */ private static void populateSunlightRegen(LitChunk chunk) { - int top = ChunkConstants.SIZE_Y - 1; + int top = Chunks.SIZE_Y - 1; /* Scan through each column in the chunk & propagate light from the top down */ - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { byte regen = 0; Block lastBlock = chunk.getBlock(x, top, z); for (int y = top - 1; y >= 0; y--) { diff --git a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java index 9df2150002b..4741edcbc51 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java @@ -15,10 +15,11 @@ */ package org.terasology.world.propagation.light; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; /** @@ -33,7 +34,7 @@ public class LightPropagationRules extends CommonLightPropagationRules { * {@inheritDoc} */ @Override - public byte getFixedValue(Block block, Vector3i pos) { + public byte getFixedValue(Block block, Vector3ic pos) { return block.getLuminance(); } @@ -54,12 +55,12 @@ public byte propagateValue(byte existingValue, Side side, Block from) { */ @Override public byte getMaxValue() { - return ChunkConstants.MAX_LIGHT; // 15 + return Chunks.MAX_LIGHT; // 15 } @Override - public byte getValue(LitChunk chunk, Vector3i pos) { - return getValue(chunk, pos.x, pos.y, pos.z); + public byte getValue(LitChunk chunk, Vector3ic pos) { + return getValue(chunk, pos.x(), pos.y(), pos.z()); } @Override @@ -68,8 +69,8 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { } @Override - public void setValue(LitChunk chunk, Vector3i pos, byte value) { - chunk.setLight(pos, value); + public void setValue(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setLight(JomlUtil.from(pos), value); } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java index 635dc6762dd..ffbebc880d5 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java @@ -15,7 +15,8 @@ */ package org.terasology.world.propagation.light; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.AbstractFullWorldView; @@ -31,12 +32,12 @@ public LightWorldView(ChunkProvider chunkProvider) { } @Override - protected byte getValueAt(LitChunk chunk, Vector3i pos) { - return chunk.getLight(pos); + protected byte getValueAt(LitChunk chunk, Vector3ic pos) { + return chunk.getLight(JomlUtil.from(pos)); } @Override - protected void setValueAt(LitChunk chunk, Vector3i pos, byte value) { - chunk.setLight(pos, value); + protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setLight(JomlUtil.from(pos), value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java index ab41aaec646..23952337ce9 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java @@ -15,10 +15,11 @@ */ package org.terasology.world.propagation.light; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.PropagatorWorldView; import org.terasology.world.propagation.SingleChunkView; @@ -44,8 +45,8 @@ public SunlightPropagationRules(LitChunk chunk) { * {@inheritDoc} */ @Override - public byte getFixedValue(Block block, Vector3i pos) { - byte lightVal = (byte) (regenWorldView.getValueAt(pos) - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD); + public byte getFixedValue(Block block, Vector3ic pos) { + byte lightVal = (byte) (regenWorldView.getValueAt(pos) - Chunks.SUNLIGHT_REGEN_THRESHOLD); return (lightVal > 0) ? lightVal : 0; } @@ -60,18 +61,18 @@ public byte propagateValue(byte existingValue, Side side, Block from) { } /** - * The maximum sunlight is given by {@link ChunkConstants#MAX_SUNLIGHT} + * The maximum sunlight is given by {@link Chunks#MAX_SUNLIGHT} *

* {@inheritDoc} */ @Override public byte getMaxValue() { - return ChunkConstants.MAX_SUNLIGHT; + return Chunks.MAX_SUNLIGHT; } @Override - public byte getValue(LitChunk chunk, Vector3i pos) { - return getValue(chunk, pos.x, pos.y, pos.z); + public byte getValue(LitChunk chunk, Vector3ic pos) { + return getValue(chunk, pos.x(), pos.y(), pos.z()); } @Override @@ -80,8 +81,8 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { } @Override - public void setValue(LitChunk chunk, Vector3i pos, byte value) { - chunk.setSunlight(pos, value); + public void setValue(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setSunlight(JomlUtil.from(pos), value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java index 7d7c6a6022f..5c93781a486 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java @@ -15,10 +15,11 @@ */ package org.terasology.world.propagation.light; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.PropagationComparison; @@ -33,37 +34,37 @@ public class SunlightRegenPropagationRules extends CommonLightPropagationRules { * {@inheritDoc} */ @Override - public byte getFixedValue(Block block, Vector3i pos) { + public byte getFixedValue(Block block, Vector3ic pos) { return 0; } /** * Sunlight goes to zero unless leaving via the bottom face. - * In that case it increases up until the maximum value in {@link ChunkConstants#MAX_SUNLIGHT_REGEN} + * In that case it increases up until the maximum value in {@link Chunks#MAX_SUNLIGHT_REGEN} *

* {@inheritDoc} */ @Override public byte propagateValue(byte existingValue, Side side, Block from) { if (side == Side.BOTTOM) { - return (existingValue == ChunkConstants.MAX_SUNLIGHT_REGEN) ? ChunkConstants.MAX_SUNLIGHT_REGEN : (byte) (existingValue + 1); + return (existingValue == Chunks.MAX_SUNLIGHT_REGEN) ? Chunks.MAX_SUNLIGHT_REGEN : (byte) (existingValue + 1); } return 0; } /** - * The maximum value of sunlight is given by {@link ChunkConstants#MAX_SUNLIGHT_REGEN} + * The maximum value of sunlight is given by {@link Chunks#MAX_SUNLIGHT_REGEN} *

* {@inheritDoc} */ @Override public byte getMaxValue() { - return ChunkConstants.MAX_SUNLIGHT_REGEN; + return Chunks.MAX_SUNLIGHT_REGEN; } @Override - public byte getValue(LitChunk chunk, Vector3i pos) { - return getValue(chunk, pos.x, pos.y, pos.z); + public byte getValue(LitChunk chunk, Vector3ic pos) { + return getValue(chunk, pos.x(), pos.y(), pos.z()); } @Override @@ -72,8 +73,8 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { } @Override - public void setValue(LitChunk chunk, Vector3i pos, byte value) { - chunk.setSunlightRegen(pos, value); + public void setValue(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setSunlightRegen(JomlUtil.from(pos), value); } /** diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java index 190d6623d1b..1e346f7a827 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java @@ -15,7 +15,8 @@ */ package org.terasology.world.propagation.light; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.AbstractFullWorldView; @@ -32,12 +33,12 @@ public SunlightRegenWorldView(ChunkProvider chunkProvider) { } @Override - protected byte getValueAt(LitChunk chunk, Vector3i pos) { - return chunk.getSunlightRegen(pos); + protected byte getValueAt(LitChunk chunk, Vector3ic pos) { + return chunk.getSunlightRegen(JomlUtil.from(pos)); } @Override - protected void setValueAt(LitChunk chunk, Vector3i pos, byte value) { - chunk.setSunlightRegen(pos, value); + protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setSunlightRegen(JomlUtil.from(pos), value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java index ead1318165f..72d4dd3a334 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java @@ -15,7 +15,8 @@ */ package org.terasology.world.propagation.light; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.AbstractFullWorldView; @@ -32,13 +33,13 @@ public SunlightWorldView(ChunkProvider chunkProvider) { } @Override - protected byte getValueAt(LitChunk chunk, Vector3i pos) { - return chunk.getSunlight(pos); + protected byte getValueAt(LitChunk chunk, Vector3ic pos) { + return chunk.getSunlight(JomlUtil.from(pos)); } @Override - protected void setValueAt(LitChunk chunk, Vector3i pos, byte value) { - chunk.setSunlight(pos, value); + protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { + chunk.setSunlight(JomlUtil.from(pos), value); } } From 7fab055c4927c7f7859d06bc210d863481d6dd78 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 10 Jan 2021 11:57:00 -0800 Subject: [PATCH 106/259] feat(JOML): migrate MovementDebugCommands (#4386) --- .../java/org/terasology/logic/debug/MovementDebugCommands.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java b/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java index 83e3d702afe..76a86c8248a 100644 --- a/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java +++ b/engine/src/main/java/org/terasology/logic/debug/MovementDebugCommands.java @@ -40,7 +40,6 @@ import org.terasology.logic.location.Location; import org.terasology.logic.location.LocationComponent; import org.terasology.logic.permission.PermissionManager; -import org.terasology.math.JomlUtil; import org.terasology.network.ClientComponent; import org.terasology.physics.engine.PhysicsEngine; import org.terasology.registry.In; @@ -139,7 +138,7 @@ public String showMovement(@Sender EntityRef client) { requiredPermission = PermissionManager.CHEAT_PERMISSION) public String showPosition(@Sender EntityRef client) { LocationComponent loc = client.getComponent(LocationComponent.class); - return "Your Position: " + loc.getWorldPosition(); + return "Your Position: " + loc.getWorldPosition(new Vector3f()); } @Command(shortDescription = "Show your Height", From 6107d906efceb19d527518096174c6c796aff70a Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Sun, 10 Jan 2021 20:43:51 +0000 Subject: [PATCH 107/259] Fix: Make the chunk relevance region iterator actually terminate (#4394) --- .../world/chunks/internal/ChunkRelevanceRegion.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java index 16ecbb1de44..026ade11375 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java @@ -203,8 +203,10 @@ public void chunkUnloaded(Vector3ic pos) { private class NeededChunksIterator implements Iterator { Vector3i nextChunkPos; + Iterator allPositions; NeededChunksIterator() { + allPositions = currentRegion.iterator(); calculateNext(); } @@ -227,7 +229,8 @@ public void remove() { private void calculateNext() { nextChunkPos = null; - for (Vector3ic regionPosition : currentRegion) { + while (allPositions.hasNext()) { + Vector3ic regionPosition = allPositions.next(); if (!relevantChunks.contains(regionPosition)) { nextChunkPos = new Vector3i(regionPosition); return; From 9f08d7a905984b44407b16909c6433c697896008 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 10 Jan 2021 14:58:22 -0800 Subject: [PATCH 108/259] feat(JOML): migrate chunk serializer (#4387) * update copyright --- .../world/chunks/internal/ChunkImpl.java | 20 +++++---- .../chunks/internal/ChunkSerializer.java | 43 +++++++------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java index 8cb59a45f20..65527e84e3f 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java @@ -21,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.math.AABB; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.BaseVector3i; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; @@ -33,6 +34,7 @@ import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkBlockIterator; import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.blockdata.TeraArray; import org.terasology.world.chunks.blockdata.TeraDenseArray16Bit; @@ -518,10 +520,10 @@ public void markReady() { public void prepareForReactivation() { if (disposed) { disposed = false; - sunlightData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); - sunlightRegenData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, - ChunkConstants.SIZE_Z); - lightData = new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); + sunlightData = new TeraDenseArray8Bit(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z); + sunlightRegenData = new TeraDenseArray8Bit(Chunks.SIZE_X, Chunks.SIZE_Y, + Chunks.SIZE_Z); + lightData = new TeraDenseArray8Bit(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z); } } @@ -561,17 +563,17 @@ public BlockRegion getRegion() { @Override public int getChunkSizeX() { - return ChunkConstants.SIZE_X; + return Chunks.SIZE_X; } @Override public int getChunkSizeY() { - return ChunkConstants.SIZE_Y; + return Chunks.SIZE_Y; } @Override public int getChunkSizeZ() { - return ChunkConstants.SIZE_Z; + return Chunks.SIZE_Z; } @Override @@ -581,7 +583,7 @@ public ChunkBlockIterator getBlockIterator() { @Override public EntityData.ChunkStore.Builder encode() { - return ChunkSerializer.encode(chunkPos, blockData, extraData); + return ChunkSerializer.encode(JomlUtil.from(chunkPos), blockData, extraData); } /** @@ -602,7 +604,7 @@ public void createSnapshot() { * @return an encoded version of the snapshot taken with {@link #createSnapshot()}. */ public EntityData.ChunkStore.Builder encodeAndReleaseSnapshot() { - EntityData.ChunkStore.Builder result = ChunkSerializer.encode(chunkPos, blockDataSnapshot, extraDataSnapshots); + EntityData.ChunkStore.Builder result = ChunkSerializer.encode(JomlUtil.from(chunkPos), blockDataSnapshot, extraDataSnapshots); this.blockDataSnapshot = null; this.extraDataSnapshots = null; return result; diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkSerializer.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkSerializer.java index c2a9f5ab6f6..db4ab87b9f1 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkSerializer.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkSerializer.java @@ -1,29 +1,19 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks.internal; import com.google.common.base.Preconditions; import com.google.protobuf.ByteString; import gnu.trove.list.TByteList; import gnu.trove.list.array.TByteArrayList; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.protobuf.EntityData; import org.terasology.world.block.BlockManager; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.blockdata.TeraArray; import org.terasology.world.chunks.blockdata.TeraDenseArray16Bit; @@ -36,14 +26,13 @@ public final class ChunkSerializer { private ChunkSerializer() { } - public static EntityData.ChunkStore.Builder encode(Vector3i pos, TeraArray blockData, TeraArray[] extraData) { + public static EntityData.ChunkStore.Builder encode(Vector3ic pos, TeraArray blockData, TeraArray[] extraData) { final EntityData.ChunkStore.Builder b = EntityData.ChunkStore.newBuilder() - .setX(pos.x).setY(pos.y).setZ(pos.z); + .setX(pos.x()).setY(pos.y()).setZ(pos.z()); b.setBlockData(runLengthEncode16(blockData)); - for (int i = 0; i < extraData.length; i++) { - b.addExtraData(runLengthEncode16(extraData[i])); + for (TeraArray extraDatum : extraData) { + b.addExtraData(runLengthEncode16(extraDatum)); } - return b; } @@ -62,7 +51,7 @@ public static Chunk decode(EntityData.ChunkStore message, BlockManager blockMana for (int i = 0; i < extraData.length; i++) { runLengthDecode(message.getExtraData(i), extraData[i]); } - return new ChunkImpl(pos, blockData, extraData, blockManager); + return new ChunkImpl(JomlUtil.from(pos), blockData, extraData, blockManager); } private static EntityData.RunLengthEncoding16 runLengthEncode16(TeraArray array) { @@ -121,7 +110,7 @@ private static EntityData.RunLengthEncoding8 runLengthEncode8(TeraArray array) { private static TeraArray runLengthDecode(EntityData.RunLengthEncoding16 data) { Preconditions.checkState(data.getValuesCount() == data.getRunLengthsCount(), "Expected same number of values as runs"); - short[] decodedData = new short[ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z]; + short[] decodedData = new short[Chunks.SIZE_X * Chunks.SIZE_Y * Chunks.SIZE_Z]; int index = 0; for (int pos = 0; pos < data.getValuesCount(); ++pos) { int length = data.getRunLengths(pos); @@ -130,12 +119,12 @@ private static TeraArray runLengthDecode(EntityData.RunLengthEncoding16 data) { decodedData[index++] = value; } } - return new TeraDenseArray16Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z, decodedData); + return new TeraDenseArray16Bit(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z, decodedData); } private static TeraArray runLengthDecode(EntityData.RunLengthEncoding8 data) { Preconditions.checkState(data.getValues().size() == data.getRunLengthsCount(), "Expected same number of values as runs"); - byte[] decodedData = new byte[ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z]; + byte[] decodedData = new byte[Chunks.SIZE_X * Chunks.SIZE_Y * Chunks.SIZE_Z]; int index = 0; ByteString.ByteIterator valueSource = data.getValues().iterator(); for (int pos = 0; pos < data.getRunLengthsCount(); ++pos) { @@ -145,9 +134,9 @@ private static TeraArray runLengthDecode(EntityData.RunLengthEncoding8 data) { decodedData[index++] = value; } } - return new TeraDenseArray8Bit(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z, decodedData); + return new TeraDenseArray8Bit(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z, decodedData); } - + /** * Decode compressed data into an existing TeraArray. * Generic w.r.t. TeraArray subclasses, allowing the data to be used for any type of TeraArray. From 643d72c358025f33d0bc3ca065520507fd32b238 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Mon, 11 Jan 2021 00:15:09 +0100 Subject: [PATCH 109/259] feat(JOML): add JOML API for BatchPropagator (partial migration) (#4391) --- .../world/propagation/BatchPropagator.java | 40 ++-- .../propagation/StandardBatchPropagator.java | 207 +++++++----------- .../SunlightRegenBatchPropagator.java | 122 +++++------ 3 files changed, 154 insertions(+), 215 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java index cc3ea0a37a7..de98f150573 100644 --- a/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java @@ -1,20 +1,9 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; +import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; @@ -55,7 +44,12 @@ public interface BatchPropagator { * @param pos The position of the block * @param block The block type */ - void propagateFrom(Vector3i pos, Block block); + void propagateFrom(Vector3ic pos, Block block); + + @Deprecated + default void propagateFrom(Vector3i pos, Block block) { + propagateFrom(JomlUtil.from(pos), block); + }; /** * Propagates a specific value out from a location @@ -63,7 +57,12 @@ public interface BatchPropagator { * @param pos The position to propagate out of * @param value The value to propagate out */ - void propagateFrom(Vector3i pos, byte value); + void propagateFrom(Vector3ic pos, byte value); + + @Deprecated + default void propagateFrom(Vector3i pos, byte value) { + propagateFrom(JomlUtil.from(pos), value); + } /** * TODO: Document @@ -71,5 +70,10 @@ public interface BatchPropagator { * @param pos The position to regenerate at * @param value The original value at this position */ - void regenerate(Vector3i pos, byte value); + void regenerate(Vector3ic pos, byte value); + + @Deprecated + default void regenerate(Vector3i pos, byte value) { + regenerate(JomlUtil.from(pos), value); + } } diff --git a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java index 317fe8ccd0f..ce1e65da538 100644 --- a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java @@ -1,35 +1,23 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.math.ChunkMath; -import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.block.BlockRegionc; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; import java.util.Arrays; import java.util.Map; import java.util.Set; +import java.util.function.Function; /** * Batch propagator that works on a set of changed blocks Works for a single given propagation ruleset @@ -42,31 +30,31 @@ public class StandardBatchPropagator implements BatchPropagator { private PropagatorWorldView world; /* Queues are stored in reverse order. Ie, strongest light is 0. */ - private Set[] reduceQueues; - private Set[] increaseQueues; + private Set[] reduceQueues; + private Set[] increaseQueues; - private Map chunkEdgeDeltas = Maps.newEnumMap(Side.class); + private Map chunkEdgeDeltas = Maps.newEnumMap(Side.class); public StandardBatchPropagator(PropagationRules rules, PropagatorWorldView world) { this.world = world; this.rules = rules; for (Side side : Side.getAllSides()) { - Vector3i delta = new Vector3i(side.getVector3i()); + Vector3i delta = new Vector3i(side.direction()); if (delta.x < 0) { - delta.x += ChunkConstants.SIZE_X; + delta.x += Chunks.SIZE_X; } else if (delta.x > 0) { - delta.x -= ChunkConstants.SIZE_X; + delta.x -= Chunks.SIZE_X; } if (delta.y < 0) { - delta.y += ChunkConstants.SIZE_Y; + delta.y += Chunks.SIZE_Y; } else if (delta.y > 0) { - delta.y -= ChunkConstants.SIZE_Y; + delta.y -= Chunks.SIZE_Y; } if (delta.z < 0) { - delta.z += ChunkConstants.SIZE_Z; + delta.z += Chunks.SIZE_Z; } else if (delta.z > 0) { - delta.z -= ChunkConstants.SIZE_Z; + delta.z -= Chunks.SIZE_Z; } chunkEdgeDeltas.put(side, delta); } @@ -102,7 +90,7 @@ public void process(Iterable blockChanges) { * @param blockChange The change that was made */ private void reviewChange(BlockChange blockChange) { - Vector3i blockChangePosition = JomlUtil.from(blockChange.getPosition()); + Vector3ic blockChangePosition = blockChange.getPosition(); byte newValue = rules.getFixedValue(blockChange.getTo(), blockChangePosition); byte existingValue = world.getValueAt(blockChangePosition); @@ -118,6 +106,7 @@ private void reviewChange(BlockChange blockChange) { } /* Process propagation out to other blocks */ + Vector3i adjPos = new Vector3i(); for (Side side : Side.getAllSides()) { PropagationComparison comparison = rules.comparePropagation(blockChange.getTo(), blockChange.getFrom(), side); @@ -125,7 +114,7 @@ private void reviewChange(BlockChange blockChange) { if (comparison.isRestricting() && existingValue > 0) { /* If the propagation of the new value is going to be lower/reduced */ reduce(blockChangePosition, existingValue); - Vector3i adjPos = side.getAdjacentPos(blockChangePosition); + side.getAdjacentPos(blockChangePosition, adjPos); byte adjValue = world.getValueAt(adjPos); if (adjValue == rules.propagateValue(existingValue, side, blockChange.getFrom())) { reduce(adjPos, adjValue); @@ -138,7 +127,7 @@ private void reviewChange(BlockChange blockChange) { queueSpreadValue(blockChangePosition, existingValue); } /* Spread it out to the block on the side */ - Vector3i adjPos = side.getAdjacentPos(blockChangePosition); + side.getAdjacentPos(blockChangePosition, adjPos); byte adjValue = world.getValueAt(adjPos); if (adjValue != PropagatorWorldView.UNAVAILABLE) { queueSpreadValue(adjPos, adjValue); @@ -147,14 +136,13 @@ private void reviewChange(BlockChange blockChange) { } } - /** * Reset a position to only it's fixed values * * @param pos The position to reset * @param oldValue The value present before reset */ - private void purge(Vector3i pos, byte oldValue) { + private void purge(Vector3ic pos, byte oldValue) { increaseQueues[rules.getMaxValue() - oldValue].remove(pos); /* Clear the value and re-propagate it if it's a positive value */ @@ -166,12 +154,12 @@ private void purge(Vector3i pos, byte oldValue) { world.setValueAt(pos, NO_VALUE); } - + Vector3i adjPos = new Vector3i(); for (Side side : Side.getAllSides()) { /* Handle this value being reset to the default by updating sides as needed */ byte expectedValue = rules.propagateValue(oldValue, side, block); - Vector3i adjPos = side.getAdjacentPos(pos); if (rules.canSpreadOutOf(block, side)) { + side.getAdjacentPos(pos, adjPos); byte adjValue = world.getValueAt(adjPos); if (adjValue == expectedValue) { Block adjBlock = world.getBlockAt(adjPos); @@ -193,11 +181,11 @@ private void processReduction() { byte oldValue = (byte) (rules.getMaxValue() - depth); while (!reduceQueues[depth].isEmpty()) { - Set toProcess = reduceQueues[depth]; + Set toProcess = reduceQueues[depth]; reduceQueues[depth] = Sets.newLinkedHashSetWithExpectedSize(toProcess.size()); /* This step will add any new reductions to to the `reduceQueues` set */ - for (Vector3i pos : toProcess) { + for (Vector3ic pos : toProcess) { purge(pos, oldValue); } } @@ -212,11 +200,11 @@ private void processIncrease() { byte value = (byte) (rules.getMaxValue() - depth); while (!increaseQueues[depth].isEmpty()) { - Set toProcess = increaseQueues[depth]; + Set toProcess = increaseQueues[depth]; increaseQueues[depth] = Sets.newLinkedHashSetWithExpectedSize(toProcess.size()); /* This step will add any new values to `increaseQueues` */ - for (Vector3i pos : toProcess) { + for (Vector3ic pos : toProcess) { push(pos, value); } } @@ -233,13 +221,14 @@ private void processIncrease() { * @param pos The initial position * @param value The value to propagate */ - private void push(Vector3i pos, byte value) { + private void push(Vector3ic pos, byte value) { Block block = world.getBlockAt(pos); + Vector3i adjPos = new Vector3i(); for (Side side : Side.getAllSides()) { byte propagatedValue = rules.propagateValue(value, side, block); if (rules.canSpreadOutOf(block, side)) { - Vector3i adjPos = side.getAdjacentPos(pos); + side.getAdjacentPos(pos, adjPos); byte adjValue = world.getValueAt(adjPos); if (adjValue < propagatedValue && adjValue != PropagatorWorldView.UNAVAILABLE) { @@ -261,7 +250,7 @@ private void push(Vector3i pos, byte value) { * @param position The position to set at * @param value The value to set the position to */ - private void increase(Vector3i position, byte value) { + private void increase(Vector3ic position, byte value) { world.setValueAt(position, value); queueSpreadValue(position, value); } @@ -272,9 +261,9 @@ private void increase(Vector3i position, byte value) { * @param position The position to set at * @param oldValue The original value at the position */ - private void reduce(Vector3i position, byte oldValue) { + private void reduce(Vector3ic position, byte oldValue) { if (oldValue > 0) { - reduceQueues[rules.getMaxValue() - oldValue].add(position); + reduceQueues[rules.getMaxValue() - oldValue].add(new Vector3i(position)); } } @@ -284,9 +273,9 @@ private void reduce(Vector3i position, byte oldValue) { * @param position The position to propagate form * @param value The value to propagate out */ - private void queueSpreadValue(Vector3i position, byte value) { + private void queueSpreadValue(Vector3ic position, byte value) { if (value > 1) { - increaseQueues[rules.getMaxValue() - value].add(position); + increaseQueues[rules.getMaxValue() - value].add(new Vector3i(position)); } } @@ -294,17 +283,17 @@ private void queueSpreadValue(Vector3i position, byte value) { * Clears all the queues and cleans up the object */ private void cleanUp() { - for (Set queue : increaseQueues) { + for (Set queue : increaseQueues) { queue.clear(); } } @Override public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boolean propagateExternal) { - IndexProvider indexProvider = createIndexProvider(side); + Function indexProvider = createIndexProvider(side); BlockRegion edgeRegion = new BlockRegion(0, 0, 0) - .setSize(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); + .setSize(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z); ChunkMath.getEdgeRegion(edgeRegion, side, edgeRegion); int[] depth = new int[edgeRegion.volume()]; @@ -313,13 +302,14 @@ public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boole propagateDepth(adjChunk, side, propagateExternal, indexProvider, edgeRegion, depth); } - private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExternal, IndexProvider indexProvider, + private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExternal, + Function indexProvider, BlockRegion edgeRegion, int[] depths) { Vector3i adjPos = new Vector3i(); int[] adjDepth = new int[depths.length]; - int dimA = (side == Side.LEFT || side == Side.RIGHT) ? ChunkConstants.SIZE_Y : ChunkConstants.SIZE_X; - int dimB = (side == Side.FRONT || side == Side.BACK) ? ChunkConstants.SIZE_Y : ChunkConstants.SIZE_Z; + int dimA = (side == Side.LEFT || side == Side.RIGHT) ? Chunks.SIZE_Y : Chunks.SIZE_X; + int dimB = (side == Side.FRONT || side == Side.BACK) ? Chunks.SIZE_Y : Chunks.SIZE_Z; ChunkMath.populateMinAdjacent2D(depths, adjDepth, dimA, dimB, !propagateExternal); if (propagateExternal) { @@ -334,56 +324,49 @@ private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExter } for (Vector3ic pos : edgeRegion) { - int depthIndex = indexProvider.getIndexFor(JomlUtil.from(pos)); + int depthIndex = indexProvider.apply(pos); int adjacentDepth = adjDepth[depthIndex]; for (int i = adjacentDepth; i < depths[depthIndex]; ++i) { - adjPos.set(side.getVector3i()); + adjPos.set(side.direction()); adjPos.mul(i + 1); - adjPos.add(JomlUtil.from(pos)); + adjPos.add(pos); adjPos.add(chunkEdgeDeltas.get(side)); byte value = rules.getValue(adjChunk, adjPos); if (value > 1) { - queueSpreadValue(adjChunk.chunkToWorldPosition(adjPos), value); + queueSpreadValue(adjChunk.chunkToWorldPosition(adjPos, new Vector3i()), value); } } } } - private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, IndexProvider indexProvider, - BlockRegion edgeRegion, int[] depths) { + private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, Function indexProvider, + BlockRegionc edgeRegion, int[] depths) { Vector3i adjPos = new Vector3i(); - for (int x = edgeRegion.minX(); x <= edgeRegion.maxX(); ++x) { - for (int y = edgeRegion.minY(); y <= edgeRegion.maxY(); ++y) { - for (int z = edgeRegion.minZ(); z <= edgeRegion.maxZ(); ++z) { - - byte expectedValue = (byte) (rules.getValue(chunk, x, y, z) - 1); - if (expectedValue < 1) { - continue; - } + for (Vector3ic pos : edgeRegion) { + byte expectedValue = (byte) (rules.getValue(chunk, pos) - 1); + if (expectedValue < 1) { + continue; + } - int depthIndex = indexProvider.getIndexFor(x, y, z); - adjPos.set(x, y, z); - adjPos.add(chunkEdgeDeltas.get(side)); - - - int depth = 0; - Block lastBlock = chunk.getBlock(x, y, z); - byte adjValue = rules.getValue(adjChunk, adjPos); - while (expectedValue > adjValue && adjValue != PropagatorWorldView.UNAVAILABLE && rules.canSpreadOutOf(lastBlock, side)) { - lastBlock = adjChunk.getBlock(adjPos); - if (rules.canSpreadInto(lastBlock, side.reverse())) { - rules.setValue(adjChunk, adjPos, expectedValue); - adjPos.add(side.getVector3i()); - depth++; - expectedValue--; - adjValue = rules.getValue(adjChunk, adjPos); - } else { - break; - } - } - depths[depthIndex] = depth; + pos.add(chunkEdgeDeltas.get(side), adjPos); + + int depthIndex = indexProvider.apply(pos); + int depth = 0; + Block lastBlock = chunk.getBlock(pos); + byte adjValue = rules.getValue(adjChunk, adjPos); + while (expectedValue > adjValue && adjValue != PropagatorWorldView.UNAVAILABLE && rules.canSpreadOutOf(lastBlock, side)) { + lastBlock = adjChunk.getBlock(adjPos); + if (rules.canSpreadInto(lastBlock, side.reverse())) { + rules.setValue(adjChunk, adjPos, expectedValue); + adjPos.add(side.direction()); + depth++; + expectedValue--; + adjValue = rules.getValue(adjChunk, adjPos); + } else { + break; } } + depths[depthIndex] = depth; } } @@ -393,67 +376,31 @@ private void propagateSide(LitChunk chunk, LitChunk adjChunk, Side side, IndexPr * @param side The side to get the provider for * @return The provider for that side */ - private IndexProvider createIndexProvider(Side side) { + private Function createIndexProvider(Side side) { switch (side) { case TOP: case BOTTOM: - return new IndexProvider() { - @Override - public int getIndexFor(Vector3i pos) { - return pos.x + ChunkConstants.SIZE_X * pos.z; - } - - @Override - public int getIndexFor(int x, int y, int z) { - return x + ChunkConstants.SIZE_X * z; - } - }; + return pos -> pos.x() + Chunks.SIZE_X * pos.z(); case LEFT: case RIGHT: - return new IndexProvider() { - @Override - public int getIndexFor(Vector3i pos) { - return pos.y + ChunkConstants.SIZE_Y * pos.z; - } - - @Override - public int getIndexFor(int x, int y, int z) { - return y + ChunkConstants.SIZE_Y * z; - } - }; + return pos -> pos.y() + Chunks.SIZE_Y * pos.z(); default: - return new IndexProvider() { - @Override - public int getIndexFor(Vector3i pos) { - return pos.x + ChunkConstants.SIZE_X * pos.y; - } - - @Override - public int getIndexFor(int x, int y, int z) { - return x + ChunkConstants.SIZE_X * y; - } - }; + return pos -> pos.x() + Chunks.SIZE_X * pos.y(); } } @Override - public void propagateFrom(Vector3i pos, Block block) { + public void propagateFrom(Vector3ic pos, Block block) { queueSpreadValue(pos, rules.getFixedValue(block, pos)); } @Override - public void propagateFrom(Vector3i pos, byte value) { + public void propagateFrom(Vector3ic pos, byte value) { queueSpreadValue(pos, value); } @Override - public void regenerate(Vector3i pos, byte value) { + public void regenerate(Vector3ic pos, byte value) { reduce(pos, value); } - - private interface IndexProvider { - int getIndexFor(Vector3i pos); - - int getIndexFor(int x, int y, int z); - } } diff --git a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java index af33b4dbe9a..7bc009ea7af 100644 --- a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java @@ -1,27 +1,15 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; import com.google.common.collect.Sets; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; import java.util.Arrays; @@ -38,8 +26,8 @@ public class SunlightRegenBatchPropagator implements BatchPropagator { private PropagatorWorldView sunlightWorld; private BatchPropagator sunlightPropagator; - private Set[] reduceQueues; - private Set[] increaseQueues; + private Set[] reduceQueues; + private Set[] increaseQueues; public SunlightRegenBatchPropagator(PropagationRules regenRules, PropagatorWorldView regenWorld, BatchPropagator sunlightPropagator, PropagatorWorldView sunlightWorld) { this.regenRules = regenRules; @@ -78,12 +66,12 @@ private void reviewChange(BlockChange blockChange) { private void reviewChangeToBottom(BlockChange blockChange) { PropagationComparison comparison = regenRules.comparePropagation(blockChange.getTo(), blockChange.getFrom(), Side.BOTTOM); - Vector3i blockChangePosition = JomlUtil.from(blockChange.getPosition()); + Vector3ic blockChangePosition = blockChange.getPosition(); if (comparison.isPermitting()) { byte existingValue = regenWorld.getValueAt(blockChangePosition); queueSpreadRegen(blockChangePosition, existingValue); } else if (comparison.isRestricting()) { - Vector3i adjPos = Side.BOTTOM.getAdjacentPos(blockChangePosition); + Vector3i adjPos = Side.BOTTOM.getAdjacentPos(blockChangePosition, new Vector3i()); byte existingValue = regenWorld.getValueAt(adjPos); reduce(adjPos, existingValue); } @@ -91,9 +79,9 @@ private void reviewChangeToBottom(BlockChange blockChange) { private void reviewChangeToTop(BlockChange blockChange) { PropagationComparison comparison = regenRules.comparePropagation(blockChange.getTo(), blockChange.getFrom(), Side.TOP); - Vector3i blockChangePosition = JomlUtil.from(blockChange.getPosition()); + Vector3ic blockChangePosition = blockChange.getPosition(); if (comparison.isPermitting()) { - Vector3i adjPos = Side.TOP.getAdjacentPos(blockChangePosition); + Vector3i adjPos = Side.TOP.getAdjacentPos(blockChangePosition, new Vector3i()); byte adjValue = regenWorld.getValueAt(adjPos); if (adjValue != PropagatorWorldView.UNAVAILABLE) { queueSpreadRegen(adjPos, adjValue); @@ -104,34 +92,34 @@ private void reviewChangeToTop(BlockChange blockChange) { } } - private void queueSpreadRegen(Vector3i position, byte value) { + private void queueSpreadRegen(Vector3ic position, byte value) { increaseQueues[value].add(position); } private void processRegenReduction() { for (byte depth = 0; depth <= regenRules.getMaxValue(); depth++) { - Set toProcess = reduceQueues[depth]; + Set toProcess = reduceQueues[depth]; toProcess.forEach(this::purge); toProcess.clear(); } } - private void purge(Vector3i pos) { + private void purge(Vector3ic pos) { int expectedValue = regenWorld.getValueAt(pos); if (expectedValue != 0) { Vector3i position = new Vector3i(pos); - for (byte i = 0; i <= ChunkConstants.MAX_SUNLIGHT_REGEN; ++i) { + for (byte i = 0; i <= Chunks.MAX_SUNLIGHT_REGEN; ++i) { if (regenWorld.getValueAt(position) == expectedValue) { regenWorld.setValueAt(position, i); - if (expectedValue - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD > 0) { - sunlightPropagator.regenerate(new Vector3i(position), (byte) (expectedValue - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD)); + if (expectedValue - Chunks.SUNLIGHT_REGEN_THRESHOLD > 0) { + sunlightPropagator.regenerate(new Vector3i(position), (byte) (expectedValue - Chunks.SUNLIGHT_REGEN_THRESHOLD)); } } else { break; } position.y--; - if (expectedValue < ChunkConstants.MAX_SUNLIGHT_REGEN) { + if (expectedValue < Chunks.MAX_SUNLIGHT_REGEN) { expectedValue++; } } @@ -140,16 +128,16 @@ private void purge(Vector3i pos) { private void processRegenIncrease() { for (byte depth = regenRules.getMaxValue(); depth >= 0; depth--) { - Set toProcess = increaseQueues[depth]; + Set toProcess = increaseQueues[depth]; - for (Vector3i pos : toProcess) { + for (Vector3ic pos : toProcess) { push(pos, depth); } toProcess.clear(); } } - private void push(Vector3i pos, byte value) { + private void push(Vector3ic pos, byte value) { byte regenValue = value; Block block = regenWorld.getBlockAt(pos); Vector3i position = new Vector3i(pos); @@ -162,7 +150,7 @@ private void push(Vector3i pos, byte value) { if (regenRules.canSpreadInto(block, Side.TOP)) { regenWorld.setValueAt(position, regenValue); reduceQueues[adjValue].remove(position); - byte sunlightValue = (byte) (regenValue - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD); + byte sunlightValue = (byte) (regenValue - Chunks.SUNLIGHT_REGEN_THRESHOLD); if (sunlightValue > 0) { byte prevValue = sunlightWorld.getValueAt(position); if (prevValue < sunlightValue) { @@ -182,7 +170,7 @@ private void push(Vector3i pos, byte value) { private void cleanUp() { } - private void reduce(Vector3i position, byte oldValue) { + private void reduce(Vector3ic position, byte oldValue) { if (oldValue > 0) { reduceQueues[oldValue].add(position); } @@ -191,25 +179,25 @@ private void reduce(Vector3i position, byte oldValue) { @Override public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boolean propagateExternal) { if (side == Side.BOTTOM) { - int[] depth = new int[ChunkConstants.SIZE_X * ChunkConstants.SIZE_Z]; + int[] depth = new int[Chunks.SIZE_X * Chunks.SIZE_Z]; int[] startingRegen = new int[depth.length]; propagateSweep(chunk, adjChunk, depth, startingRegen); int[] adjDepths = new int[depth.length]; - ChunkMath.populateMinAdjacent2D(depth, adjDepths, ChunkConstants.SIZE_X, ChunkConstants.SIZE_Z, !propagateExternal); + ChunkMath.populateMinAdjacent2D(depth, adjDepths, Chunks.SIZE_X, Chunks.SIZE_Z, !propagateExternal); if (propagateExternal) { - for (int z = 0; z < ChunkConstants.SIZE_Z; ++z) { - adjDepths[z * ChunkConstants.SIZE_X] = 0; - adjDepths[ChunkConstants.SIZE_X - 1 + z * ChunkConstants.SIZE_X] = 0; + for (int z = 0; z < Chunks.SIZE_Z; ++z) { + adjDepths[z * Chunks.SIZE_X] = 0; + adjDepths[Chunks.SIZE_X - 1 + z * Chunks.SIZE_X] = 0; } - for (int x = 0; x < ChunkConstants.SIZE_X; ++x) { + for (int x = 0; x < Chunks.SIZE_X; ++x) { adjDepths[x] = 0; - adjDepths[x + ChunkConstants.SIZE_X * (ChunkConstants.SIZE_Z - 1)] = 0; + adjDepths[x + Chunks.SIZE_X * (Chunks.SIZE_Z - 1)] = 0; } } int[] adjStartingRegen = new int[depth.length]; - ChunkMath.populateMinAdjacent2D(startingRegen, adjStartingRegen, ChunkConstants.SIZE_X, ChunkConstants.SIZE_Z, true); + ChunkMath.populateMinAdjacent2D(startingRegen, adjStartingRegen, Chunks.SIZE_X, Chunks.SIZE_Z, true); markForPropagation(adjChunk, depth, startingRegen, adjDepths, adjStartingRegen); } @@ -217,30 +205,30 @@ public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boole private void markForPropagation(LitChunk toChunk, int[] depth, int[] startingRegen, int[] adjDepths, int[] adjStartingRegen) { Vector3i pos = new Vector3i(); - for (int z = 0; z < ChunkConstants.SIZE_Z; ++z) { - for (int x = 0; x < ChunkConstants.SIZE_X; ++x) { - int depthIndex = x + ChunkConstants.SIZE_X * z; + for (int z = 0; z < Chunks.SIZE_Z; ++z) { + for (int x = 0; x < Chunks.SIZE_X; ++x) { + int depthIndex = x + Chunks.SIZE_X * z; int start = startingRegen[depthIndex]; int adjStart = adjStartingRegen[depthIndex]; if (start - adjStart > 1) { - int initialDepth = Math.max(ChunkConstants.SUNLIGHT_REGEN_THRESHOLD - start, 0); + int initialDepth = Math.max(Chunks.SUNLIGHT_REGEN_THRESHOLD - start, 0); int finalDepth = depth[depthIndex]; - int strength = Math.min(start + initialDepth - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD + 1, ChunkConstants.MAX_SUNLIGHT); + int strength = Math.min(start + initialDepth - Chunks.SUNLIGHT_REGEN_THRESHOLD + 1, Chunks.MAX_SUNLIGHT); for (int i = initialDepth; i <= finalDepth; ++i) { - sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, ChunkConstants.SIZE_Y - i - 1, z), + sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, Chunks.SIZE_Y - i - 1, z), (byte) (strength)); - if (strength < ChunkConstants.MAX_SUNLIGHT) { + if (strength < Chunks.MAX_SUNLIGHT) { strength++; } } } else { - int initialDepth = Math.max(adjDepths[depthIndex], ChunkConstants.SUNLIGHT_REGEN_THRESHOLD - start); - byte strength = (byte) Math.min(ChunkConstants.MAX_SUNLIGHT, start + initialDepth - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD + 1); + int initialDepth = Math.max(adjDepths[depthIndex], Chunks.SUNLIGHT_REGEN_THRESHOLD - start); + byte strength = (byte) Math.min(Chunks.MAX_SUNLIGHT, start + initialDepth - Chunks.SUNLIGHT_REGEN_THRESHOLD + 1); for (int i = initialDepth; i <= depth[depthIndex]; ++i) { - sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, ChunkConstants.SIZE_Y - i - 1, z), strength); - if (strength < ChunkConstants.MAX_SUNLIGHT) { + sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, Chunks.SIZE_Y - i - 1, z), strength); + if (strength < Chunks.MAX_SUNLIGHT) { strength++; } pos.y--; @@ -253,28 +241,28 @@ private void markForPropagation(LitChunk toChunk, int[] depth, int[] startingReg private void propagateSweep(LitChunk fromChunk, LitChunk toChunk, int[] depth, int[] startingRegen) { Vector3i pos = new Vector3i(); - for (int z = 0; z < ChunkConstants.SIZE_Z; ++z) { - for (int x = 0; x < ChunkConstants.SIZE_X; ++x) { - int depthIndex = x + ChunkConstants.SIZE_X * z; + for (int z = 0; z < Chunks.SIZE_Z; ++z) { + for (int x = 0; x < Chunks.SIZE_X; ++x) { + int depthIndex = x + Chunks.SIZE_X * z; startingRegen[depthIndex] = regenRules.getValue(fromChunk, new Vector3i(x, 0, z)); - byte expectedValue = (byte) Math.min(startingRegen[depthIndex] + 1, ChunkConstants.MAX_SUNLIGHT_REGEN); + byte expectedValue = (byte) Math.min(startingRegen[depthIndex] + 1, Chunks.MAX_SUNLIGHT_REGEN); Block fromBlock = fromChunk.getBlock(x, 0, z); - Block toBlock = toChunk.getBlock(x, ChunkConstants.SIZE_Y - 1, z); + Block toBlock = toChunk.getBlock(x, Chunks.SIZE_Y - 1, z); if (!(regenRules.canSpreadOutOf(fromBlock, Side.BOTTOM) && regenRules.canSpreadInto(toBlock, Side.TOP))) { continue; } byte predictedValue = 0; - pos.set(x, ChunkConstants.SIZE_Y - 1, z); + pos.set(x, Chunks.SIZE_Y - 1, z); int currentValue = regenRules.getValue(toChunk, pos); while (currentValue == predictedValue && expectedValue > currentValue) { regenRules.setValue(toChunk, pos, expectedValue); depth[depthIndex]++; - byte sunlight = (byte) (expectedValue - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD); - if (sunlight > 0 && sunlight > toChunk.getSunlight(pos)) { - toChunk.setSunlight(pos, sunlight); + byte sunlight = (byte) (expectedValue - Chunks.SUNLIGHT_REGEN_THRESHOLD); + if (sunlight > 0 && sunlight > toChunk.getSunlight(JomlUtil.from(pos))) { + toChunk.setSunlight(JomlUtil.from(pos), sunlight); } - if (expectedValue < ChunkConstants.MAX_SUNLIGHT_REGEN) { + if (expectedValue < Chunks.MAX_SUNLIGHT_REGEN) { expectedValue++; } predictedValue++; @@ -286,17 +274,17 @@ private void propagateSweep(LitChunk fromChunk, LitChunk toChunk, int[] depth, i } @Override - public void propagateFrom(Vector3i pos, Block block) { + public void propagateFrom(Vector3ic pos, Block block) { throw new UnsupportedOperationException(); } @Override - public void propagateFrom(Vector3i pos, byte value) { + public void propagateFrom(Vector3ic pos, byte value) { throw new UnsupportedOperationException(); } @Override - public void regenerate(Vector3i pos, byte value) { + public void regenerate(Vector3ic pos, byte value) { throw new UnsupportedOperationException(); } From 703411ecf2a26f4317ad25c9992f1b024d355059 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 11 Jan 2021 02:02:03 -0800 Subject: [PATCH 110/259] perf(optimize): optimize iterator for block region (#4399) --- .../terasology/world/block/BlockRegion.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegion.java b/engine/src/main/java/org/terasology/world/block/BlockRegion.java index c9b89373ef0..42e754d01eb 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegion.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegion.java @@ -10,6 +10,7 @@ import org.joml.Vector3ic; import org.terasology.math.Side; +import java.util.Collections; import java.util.Iterator; import java.util.Optional; @@ -112,39 +113,35 @@ public BlockRegion(BlockRegionc source) { @Override public Iterator iterator() { + if (!isValid()) { + return Collections.emptyIterator(); + } return new Iterator() { private Vector3i current = null; private final Vector3i next = getMin(new Vector3i()); public boolean findNext() { - if (current.equals(next)) { - next.z++; - if (next.z > maxZ) { - next.z = minZ; - next.y++; - if (next.y > maxY) { - next.y = minY; - next.x++; - } + next.z++; + if (next.z > maxZ) { + next.z = minZ; + next.y++; + if (next.y > maxY) { + next.y = minY; + next.x++; } - return contains(next); } - return true; + return next.x <= maxX; } @Override public boolean hasNext() { - if (!isValid()) { - return false; - } if (current == null) { return true; } - - if (current.equals(next)) { + if (current.equals(next.x(), next.y(), next.z())) { return findNext(); } - return contains(next); + return next.x <= maxX; } @Override @@ -153,8 +150,7 @@ public Vector3ic next() { current = new Vector3i(next); return next; } - - if (current.equals(next)) { + if (current.equals(next.x(), next.y(), next.z())) { if (findNext()) { return next; } From 91b787cbd68ae6e6fe5b75ff83c68cf3910ec63a Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Mon, 11 Jan 2021 11:58:48 +0100 Subject: [PATCH 111/259] feat(TypeHandler): Add GenericMapTypeHandler for `Map` (#4377) * doc: add short description to GenericMapTypeHandler * test: correct failing test `Map` is no longer invalid, so I turned it into a test for checking that the generic map handler is used. --- .../typeHandling/TypeHandlerLibrary.java | 4 +- .../coreTypes/GenericMapTypeHandler.java | 86 +++++++++++++++++++ ...actory.java => MapTypeHandlerFactory.java} | 21 +++-- .../typeHandling/TypeHandlerLibraryTest.java | 9 +- ...st.java => MapTypeHandlerFactoryTest.java} | 17 +++- 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/GenericMapTypeHandler.java rename subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/{StringMapTypeHandlerFactory.java => MapTypeHandlerFactory.java} (68%) rename subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/{StringMapTypeHandlerFactoryTest.java => MapTypeHandlerFactoryTest.java} (81%) diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java index 664894d22f1..0bcf80f3da6 100644 --- a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibrary.java @@ -23,7 +23,7 @@ import org.terasology.persistence.typeHandling.coreTypes.factories.CollectionTypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.factories.EnumTypeHandlerFactory; import org.terasology.persistence.typeHandling.coreTypes.factories.ObjectFieldMapTypeHandlerFactory; -import org.terasology.persistence.typeHandling.coreTypes.factories.StringMapTypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.factories.MapTypeHandlerFactory; import org.terasology.persistence.typeHandling.reflection.ReflectionsSandbox; import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; import org.terasology.reflection.TypeInfo; @@ -105,7 +105,7 @@ static void populateBuiltInHandlers(TypeHandlerLibrary typeHandlerLibrary) { typeHandlerLibrary.addTypeHandler(byte[].class, new ByteArrayTypeHandler()); typeHandlerLibrary.addTypeHandlerFactory(new EnumTypeHandlerFactory()); - typeHandlerLibrary.addTypeHandlerFactory(new StringMapTypeHandlerFactory()); + typeHandlerLibrary.addTypeHandlerFactory(new MapTypeHandlerFactory()); } /** diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/GenericMapTypeHandler.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/GenericMapTypeHandler.java new file mode 100644 index 00000000000..92b789e388b --- /dev/null +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/GenericMapTypeHandler.java @@ -0,0 +1,86 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.persistence.typeHandling.coreTypes; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.persistence.typeHandling.PersistedData; +import org.terasology.persistence.typeHandling.PersistedDataSerializer; +import org.terasology.persistence.typeHandling.TypeHandler; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * A type handler for generic maps delegating (de-)serialization to the respective type handler for the key type {@code + * K} and the value type {@code V}. + * + * @param the type of keys; requires a {@code TypeHandler} + * @param the type of mapped values; requires a {@code TypeHandler} + */ +public class GenericMapTypeHandler extends TypeHandler> { + + private static final Logger logger = LoggerFactory.getLogger(GenericMapTypeHandler.class); + + private static final String KEY = "key"; + private static final String VALUE = "value"; + + private final TypeHandler keyHandler; + private final TypeHandler valueHandler; + + public GenericMapTypeHandler(TypeHandler keyHandler, TypeHandler valueHandler) { + this.keyHandler = Preconditions.checkNotNull(keyHandler); + this.valueHandler = Preconditions.checkNotNull(valueHandler); + } + + @Override + protected PersistedData serializeNonNull(Map data, PersistedDataSerializer serializer) { + final List entries = data.entrySet().stream() + .map(entry -> serializeEntry(entry, serializer)) + .collect(Collectors.toList()); + return serializer.serialize(entries); + } + + private PersistedData serializeEntry(Map.Entry entry, PersistedDataSerializer serializer) { + PersistedData key = keyHandler.serialize(entry.getKey(), serializer); + PersistedData value = valueHandler.serialize(entry.getValue(), serializer); + + Map result = Maps.newLinkedHashMap(); + if (!key.isNull()) { + result.put(KEY, key); + result.put(VALUE, value); + } + return serializer.serialize(result); + } + + @Override + public Optional> deserialize(PersistedData data) { + if (!data.isArray()) { + return Optional.empty(); + } + + Map result = Maps.newLinkedHashMap(); + + for (PersistedData entry : data.getAsArray()) { + final Optional key = keyHandler.deserialize(entry.getAsValueMap().get(KEY)); + final Optional value = valueHandler.deserialize(entry.getAsValueMap().get(VALUE)); + + if (key.isPresent()) { + if (value.isPresent()) { + result.put(key.get(), value.get()); + } else { + logger.warn("Missing field '{}' for entry '{}'", VALUE, data.getAsString()); + } + } else { + logger.warn("Missing field '{}' for entry '{}'", KEY, data.getAsString()); + } + } + + return Optional.of(result); + } +} diff --git a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactory.java similarity index 68% rename from subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java rename to subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactory.java index bb6fc89f640..2011ff02149 100644 --- a/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactory.java +++ b/subsystems/TypeHandlerLibrary/src/main/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactory.java @@ -7,6 +7,7 @@ import org.terasology.persistence.typeHandling.TypeHandler; import org.terasology.persistence.typeHandling.TypeHandlerContext; import org.terasology.persistence.typeHandling.TypeHandlerFactory; +import org.terasology.persistence.typeHandling.coreTypes.GenericMapTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.StringMapTypeHandler; import org.terasology.reflection.ReflectionUtil; @@ -16,7 +17,7 @@ import java.util.Map; import java.util.Optional; -public class StringMapTypeHandlerFactory implements TypeHandlerFactory { +public class MapTypeHandlerFactory implements TypeHandlerFactory { private static final Logger LOGGER = LoggerFactory.getLogger(StringMapTypeHandler.class); @SuppressWarnings("unchecked") @@ -29,9 +30,6 @@ public Optional> create(TypeInfo typeInfo, TypeHandlerCont Type keyType = ReflectionUtil.getTypeParameterForSuper(typeInfo.getType(), Map.class, 0); Type valueType = ReflectionUtil.getTypeParameterForSuper(typeInfo.getType(), Map.class, 1); - if (!String.class.equals(keyType)) { - return Optional.empty(); - } if (valueType == null) { LOGGER.error("Map is not parameterized and cannot be serialized"); @@ -50,6 +48,19 @@ public Optional> create(TypeInfo typeInfo, TypeHandlerCont context ); - return Optional.of((TypeHandler) new StringMapTypeHandler<>(valueTypeHandler)); + if (String.class.equals(keyType)) { + return Optional.of((TypeHandler) new StringMapTypeHandler<>(valueTypeHandler)); + } else { + Optional> declaredKeyTypeHandler = + context.getTypeHandlerLibrary().getTypeHandler(keyType); + TypeInfo keyTypeInfo = TypeInfo.of(keyType); + @SuppressWarnings({"unchecked"}) + TypeHandler keyTypeHandler = new RuntimeDelegatingTypeHandler( + declaredKeyTypeHandler.orElse(null), + keyTypeInfo, + context + ); + return Optional.of((TypeHandler) new GenericMapTypeHandler<>(keyTypeHandler, valueTypeHandler)); + } } } diff --git a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java index 3a76bd01ceb..44db9eeb935 100644 --- a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryTest.java @@ -7,6 +7,7 @@ import org.reflections.Reflections; import org.terasology.persistence.typeHandling.coreTypes.CollectionTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.EnumTypeHandler; +import org.terasology.persistence.typeHandling.coreTypes.GenericMapTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.ObjectFieldMapTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.RuntimeDelegatingTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.StringMapTypeHandler; @@ -78,12 +79,12 @@ void testStringMapHandler() { } @Test - void testInvalidTypeHandler() { - Optional>> handler = + void testGenericMapHandler() { + TypeHandler> handler = typeHandlerLibrary.getTypeHandler(new TypeInfo>() { - }); + }).get(); - assertFalse(handler.isPresent()); + assertTrue(handler instanceof GenericMapTypeHandler); } @Test diff --git a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactoryTest.java similarity index 81% rename from subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java rename to subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactoryTest.java index 5a6b4d04b02..c66e0da4eee 100644 --- a/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/StringMapTypeHandlerFactoryTest.java +++ b/subsystems/TypeHandlerLibrary/src/test/java/org/terasology/persistence/typeHandling/coreTypes/factories/MapTypeHandlerFactoryTest.java @@ -7,6 +7,7 @@ import org.terasology.persistence.typeHandling.TypeHandler; import org.terasology.persistence.typeHandling.TypeHandlerContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.persistence.typeHandling.coreTypes.GenericMapTypeHandler; import org.terasology.persistence.typeHandling.coreTypes.StringMapTypeHandler; import org.terasology.persistence.typeHandling.reflection.SerializationSandbox; import org.terasology.reflection.TypeInfo; @@ -21,9 +22,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -class StringMapTypeHandlerFactoryTest { +class MapTypeHandlerFactoryTest { private final TypeHandlerLibrary typeHandlerLibrary = mock(TypeHandlerLibrary.class); - private final StringMapTypeHandlerFactory typeHandlerFactory = new StringMapTypeHandlerFactory(); + private final MapTypeHandlerFactory typeHandlerFactory = new MapTypeHandlerFactory(); private final TypeHandlerContext context = new TypeHandlerContext(typeHandlerLibrary, mock(SerializationSandbox.class)); @@ -65,4 +66,16 @@ class IntMap extends HashMap {} // Verify that the Integer TypeHandler was loaded from the TypeHandlerLibrary verify(typeHandlerLibrary).getTypeHandler(ArgumentMatchers.eq(TypeInfo.of(Integer.class).getType())); } + + + @Test + void testGenericMap() { + TypeInfo> listTypeInfo = new TypeInfo>() {}; + + Optional>> typeHandler = + typeHandlerFactory.create(listTypeInfo, context); + + assertTrue(typeHandler.isPresent()); + assertTrue(typeHandler.get() instanceof GenericMapTypeHandler); + } } From 653d20949c0eaae5a5312c0dd91786b74b66e9fb Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Tue, 12 Jan 2021 17:12:52 +0000 Subject: [PATCH 112/259] Add the dest argument to Chunks.toRelative in ChunkViewCoreImpl (#4402) --- .../org/terasology/world/internal/ChunkViewCoreImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java index 2065d04e7d0..202049d4281 100644 --- a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java @@ -135,7 +135,7 @@ public void setBlock(Vector3ic pos, Block type) { public void setBlock(int blockX, int blockY, int blockZ, Block type) { if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setBlock(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize), type); + chunks[chunkIndex].setBlock(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), type); } else { logger.warn("Attempt to modify block outside of the view"); } @@ -183,7 +183,7 @@ public int getExtraData(int index, int blockX, int blockY, int blockZ) { } int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize)); + return chunks[chunkIndex].getExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())); } @Override @@ -195,7 +195,7 @@ public void setExtraData(int index, Vector3ic pos, int value) { public void setExtraData(int index, int blockX, int blockY, int blockZ, int value) { if (blockRegion.contains(blockX, blockY, blockZ)) { int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize), value); + chunks[chunkIndex].setExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), value); } else { throw new IllegalStateException("Attempted to modify extra data though an unlocked view"); } From 8f33359409723456f1eb768981492755cb2e18e6 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 12 Jan 2021 14:24:46 -0800 Subject: [PATCH 113/259] feat(JOML): migrate ChunkProvider#getChunk(Vector3ic) (#4396) * feat(JOML): migrate ChunkProvider#getChunk(Vector3ic) * update ArgumentMatcher * update test cases * update BetweenChunkPropagationTest --- .../persistence/internal/StorageManagerTest.java | 7 ++++--- .../propagation/BetweenChunkPropagationTest.java | 6 ++++++ .../org/terasology/world/chunks/ChunkProvider.java | 11 +++++++++++ .../chunks/localChunkProvider/LocalChunkProvider.java | 1 + .../remoteChunkProvider/RemoteChunkProvider.java | 10 +++++----- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java index 1a0cddb6de9..97e8e4a8699 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java @@ -21,13 +21,14 @@ import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.joml.Vector3f; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; @@ -87,7 +88,7 @@ public class StorageManagerTest extends TerasologyTestingEnvironment { public static final String PLAYER_ID = "someId"; - public static final Vector3i CHUNK_POS = new Vector3i(1, 2, 3); + public static final Vector3ic CHUNK_POS = new Vector3i(1, 2, 3); private static File temporaryFolder; @@ -303,7 +304,7 @@ public void testChunkSurvivesStorageSaveAndRestore() throws Exception { chunk.markReady(); ChunkProvider chunkProvider = mock(ChunkProvider.class); when(chunkProvider.getAllChunks()).thenReturn(Arrays.asList(chunk)); - when(chunkProvider.getChunk(Matchers.any(org.terasology.math.geom.Vector3i.class))).thenReturn(chunk); + when(chunkProvider.getChunk(ArgumentMatchers.any(Vector3ic.class))).thenReturn(chunk); CoreRegistry.put(ChunkProvider.class, chunkProvider); boolean storeChunkInZips = true; diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java index 5463a9b10df..69903278642 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java @@ -23,6 +23,7 @@ import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.math.JomlUtil; import org.terasology.math.Region3i; import org.terasology.math.Side; import org.terasology.math.geom.Vector3i; @@ -263,6 +264,11 @@ public Chunk getChunk(Vector3i chunkPos) { return chunks.get(chunkPos); } + @Override + public Chunk getChunk(Vector3ic chunkPos) { + return chunks.get(JomlUtil.from(chunkPos)); + } + @Override public void dispose() { // do nothing diff --git a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java index 29d991cb864..16dfe8558a2 100644 --- a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java @@ -86,9 +86,20 @@ public interface ChunkProvider { * * @param chunkPos The position of the chunk to obtain * @return The chunk, or null if the chunk is not ready + * @deprecated use {@link #getChunk(org.joml.Vector3ic)} instead. TODO replace with joml. */ + @Deprecated Chunk getChunk(Vector3i chunkPos); + /** + * Returns the chunk at the given position if possible. + * + * @param chunkPos The position of the chunk to obtain + * @return The chunk, or null if the chunk is not ready + */ + Chunk getChunk(Vector3ic chunkPos); + + /** * Disposes the chunk provider, cleaning up all chunks and other assets it is using */ diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 65f49703952..35d28c49081 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -373,6 +373,7 @@ public Chunk getChunk(Vector3i pos) { return null; } + @Override public Chunk getChunk(org.joml.Vector3ic pos) { return getChunk(JomlUtil.from(pos)); } diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 6032129dddb..31ace941a6e 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -144,6 +144,11 @@ public Chunk getChunk(Vector3i chunkPos) { return null; } + @Override + public Chunk getChunk(org.joml.Vector3ic pos) { + return getChunk(JomlUtil.from(pos)); + } + @Override public boolean isChunkReady(Vector3i pos) { Chunk chunk = chunkCache.get(pos); @@ -162,11 +167,6 @@ public void dispose() { loadingPipeline.shutdown(); } - - public Chunk getChunk(org.joml.Vector3ic pos) { - return getChunk(JomlUtil.from(pos)); - } - @Override public boolean reloadChunk(Vector3i pos) { return false; From 8b1c0200ef2b87c5e98b5f91d992073baaa98ff0 Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Wed, 13 Jan 2021 23:19:13 +0300 Subject: [PATCH 114/259] feature(JMH): Migrate benchmarks to JMH (#4401) * build(jmh): add jmh plugin and move benchmarks to jmh sourceset * refactor(jmh): migrate entitySystem's benchmarks to jmh. * chore(jmh): update javaassist to support java 11 * fix(jmh): fix OOM on EntitySystem's benchmarks and fix parameters. * feature(jmh): migrate ReflectFactory's benchmarks to JMH * feature(jmh): add direct variant to ReflectionFactoryBenchmark for comparation * feature(jmh): migrate `TeraArray`'s benchmarks to JHM. * chore: remove old benchmark's code --- engine/build.gradle | 32 ++- .../benchmark/AbstractBenchmark.java | 69 ----- .../benchmark/BasicBenchmarkResult.java | 47 --- .../org/terasology/benchmark/Benchmark.java | 39 --- .../benchmark/BenchmarkCallback.java | 38 --- .../terasology/benchmark/BenchmarkError.java | 45 --- .../terasology/benchmark/BenchmarkResult.java | 186 ------------ .../org/terasology/benchmark/Benchmarks.java | 269 ------------------ .../benchmark/PrintToConsoleCallback.java | 75 ----- .../chunks/arrays/BenchmarkTeraArray.java | 60 ---- ...nchmarkTeraArrayDeserializeFromBuffer.java | 62 ---- .../chunks/arrays/BenchmarkTeraArrayRead.java | 48 ---- .../BenchmarkTeraArraySerialization.java | 47 --- .../BenchmarkTeraArraySerializeObject.java | 65 ----- .../BenchmarkTeraArraySerializeToBuffer.java | 62 ---- ...nchmarkTeraArraySerializeToByteString.java | 64 ----- ...eraArraySerializeToStreamViaByteArray.java | 72 ----- ...kTeraArraySerializeToStreamViaChannel.java | 74 ----- .../arrays/BenchmarkTeraArrayWrite.java | 46 --- .../chunks/arrays/TeraArraysBenchmark.java | 78 ----- .../chunks/cache/BenchmarkChunkCache.java | 64 ----- .../chunks/cache/ChunkCachesBenchmark.java | 27 -- .../entitySystem/EntityCreateBenchmark.java | 62 ---- .../entitySystem/EntitySystemBenchmark.java | 46 --- .../IterateMultipleComponentBenchmark.java | 75 ----- .../IterateSingleComponentBenchmark.java | 79 ----- .../reflectFactory/ConstructionBenchmark.java | 53 ---- .../reflectFactory/FieldAccessBenchmark.java | 58 ---- .../GetterSetterAccessBenchmark.java | 57 ---- .../ReflectFactoryBenchmark.java | 52 ---- .../chunks/arrays/TeraArrayBenchmark.java | 158 ++++++++++ .../entitySystem/EntityCreateBenchmark.java | 61 ++++ .../IterateComponentsBenchmark.java | 71 +++++ .../reflectFactory/GetterSetterComponent.java | 0 .../ReflectionFactoryBenchmark.java | 174 +++++++++++ 35 files changed, 487 insertions(+), 2028 deletions(-) delete mode 100644 engine/src/dev/java/org/terasology/benchmark/AbstractBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/BasicBenchmarkResult.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/Benchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/BenchmarkCallback.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/BenchmarkError.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/BenchmarkResult.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/Benchmarks.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/PrintToConsoleCallback.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArray.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayRead.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToByteString.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayWrite.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/cache/BenchmarkChunkCache.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/chunks/cache/ChunkCachesBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/entitySystem/EntitySystemBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateMultipleComponentBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateSingleComponentBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/reflectFactory/ConstructionBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/reflectFactory/FieldAccessBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterAccessBenchmark.java delete mode 100644 engine/src/dev/java/org/terasology/benchmark/reflectFactory/ReflectFactoryBenchmark.java create mode 100644 engine/src/jmh/java/org/terasology/benchmark/chunks/arrays/TeraArrayBenchmark.java create mode 100644 engine/src/jmh/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java create mode 100644 engine/src/jmh/java/org/terasology/benchmark/entitySystem/IterateComponentsBenchmark.java rename engine/src/{dev => jmh}/java/org/terasology/benchmark/reflectFactory/GetterSetterComponent.java (100%) create mode 100644 engine/src/jmh/java/org/terasology/benchmark/reflectFactory/ReflectionFactoryBenchmark.java diff --git a/engine/build.gradle b/engine/build.gradle index a0435a4e256..6b17fd89528 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 // The engine build is the primary Java project and has the primary list of dependencies @@ -50,13 +50,6 @@ def convertGitBranch = { gitBranch -> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sourceSets { - main.java { - // dev/ holds things that are neither unit tests nor application code. - // For notes about whether it should be its own source set, see - // see https://github.com/MovingBlocks/Terasology/pull/4021 - srcDir("src/dev/java") - } - // Adjust output path (changed with the Gradle 6 upgrade, this puts it back) main.java.outputDir = new File("$buildDir/classes") } @@ -90,7 +83,7 @@ dependencies { // Java magic implementation group: 'net.java.dev.jna', name: 'jna-platform', version: '5.6.0' implementation group: 'org.reflections', name: 'reflections', version: '0.9.10' - implementation group: 'org.javassist', name: 'javassist', version: '3.20.0-GA' + implementation group: 'org.javassist', name: 'javassist', version: '3.27.0-GA' implementation group: 'com.esotericsoftware', name: 'reflectasm', version: '1.11.1' // Graphics, 3D, UI, etc @@ -191,6 +184,27 @@ task cleanReflections(type: Delete) { delete cacheReflections.outputs.files } +// JMH related tasks + +sourceSets { + jmh { + java.srcDirs = ['src/jmh/java'] + resources.srcDirs = ['src/jmh/resources'] + compileClasspath += sourceSets.main.runtimeClasspath + } +} + +task jmh(type: JavaExec, dependsOn: jmhClasses) { + main = 'org.openjdk.jmh.Main' + classpath = sourceSets.jmh.compileClasspath + sourceSets.jmh.runtimeClasspath +} + +dependencies { + jmhAnnotationProcessor group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.27' + jmhImplementation 'org.openjdk.jmh:jmh-core:1.27' + jmhImplementation 'org.openjdk.jmh:jmh-generator-annprocess:1.27' +} + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Version file stuff // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/engine/src/dev/java/org/terasology/benchmark/AbstractBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/AbstractBenchmark.java deleted file mode 100644 index d451df40110..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/AbstractBenchmark.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark; - -import java.util.Arrays; - -/** - * - */ -public abstract class AbstractBenchmark implements Benchmark { - - private String title; - private int warmupRepetitions; - private int[] reps; - - public AbstractBenchmark(String title, int warmupReps, int[] reps) { - this.title = title; - this.warmupRepetitions = warmupReps; - this.reps = Arrays.copyOf(reps, reps.length); - } - - @Override - public String getTitle() { - return title; - } - - @Override - public int getWarmupRepetitions() { - return warmupRepetitions; - } - - @Override - public int[] getRepetitions() { - return Arrays.copyOf(reps, reps.length); - } - - @Override - public void setup() { - } - - @Override - public void prerun() { - } - - @Override - public abstract void run(); - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/BasicBenchmarkResult.java b/engine/src/dev/java/org/terasology/benchmark/BasicBenchmarkResult.java deleted file mode 100644 index 12b9f1e7ab2..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/BasicBenchmarkResult.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - - -/** - * BasicBenchmarkResult extends BenchmarkResult and adds three basic columns for pretty printing. - * - */ -public class BasicBenchmarkResult extends BenchmarkResult { - - public BasicBenchmarkResult(Benchmark benchmark) { - super(benchmark); - addColumn(new Column(this, Alignment.RIGHT, "#") { - @Override - public String getValueInternal(int rep) { - return String.valueOf(rep + 1); - } - }); - addColumn(new Column(this, Alignment.RIGHT, "Repetitions") { - @Override - protected String getValueInternal(int rep) { - return String.valueOf(owner.getRepetitions(rep)); - } - }); - addColumn(new Column(this, Alignment.RIGHT, "Time in ms") { - @Override - protected String getValueInternal(int rep) { - return String.valueOf(owner.getRunTime(rep)); - } - }); - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/Benchmark.java b/engine/src/dev/java/org/terasology/benchmark/Benchmark.java deleted file mode 100644 index 71b78ac6dc8..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/Benchmark.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -/** - * Benchmark is an abstract class which is used to implement one particular benchmark. - * - */ -public interface Benchmark { - - String getTitle(); - - int getWarmupRepetitions(); - - int[] getRepetitions(); - - void setup(); - - void prerun(); - - void run(); - - void postrun(); - - void finish(boolean aborted); -} diff --git a/engine/src/dev/java/org/terasology/benchmark/BenchmarkCallback.java b/engine/src/dev/java/org/terasology/benchmark/BenchmarkCallback.java deleted file mode 100644 index d33c9d3ae7e..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/BenchmarkCallback.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -/** - * BenchmarkCallback allows to watch the progress of the execution of one or many benchmarks. - * - */ -public interface BenchmarkCallback { - - void begin(Benchmark benchmark, int benchmarkIndex, int benchmarkCount); - - void warmup(Benchmark benchmark, boolean finished); - - void progress(Benchmark benchmark, double percent); - - void success(BenchmarkResult result); - - void aborted(BenchmarkResult result); - - void error(BenchmarkError.Type type, Exception e, BenchmarkResult result); - - void fatal(Exception e); - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/BenchmarkError.java b/engine/src/dev/java/org/terasology/benchmark/BenchmarkError.java deleted file mode 100644 index 55e1cd6de78..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/BenchmarkError.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -import com.google.common.base.Preconditions; - -/** - * BenchmarkError encapsulates an error that occurred during a benchmark. - * It stores the type of the error and the exception object. - * - */ -public class BenchmarkError { - - public enum Type { - Setup(true), Warmup(true), PreRun(true), Run(true), PostRun(true), Finish(false); - - public final boolean abort; - - Type(boolean abort) { - this.abort = abort; - } - } - - public final Type type; - public final Exception error; - - public BenchmarkError(Type type, Exception error) { - this.type = Preconditions.checkNotNull(type); - this.error = Preconditions.checkNotNull(error); - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/BenchmarkResult.java b/engine/src/dev/java/org/terasology/benchmark/BenchmarkResult.java deleted file mode 100644 index e3e21742789..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/BenchmarkResult.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; - -import java.util.Iterator; -import java.util.List; - -/** - * BenchmarkResult records the results and the errors of the execution of one particular benchmark. - * It also maintains a list of columns which are very useful for pretty printing the results. - * - */ -public abstract class BenchmarkResult { - - private final List> columns = Lists.newLinkedList(); - - private final Class benchmarkClass; - private final String title; - private final int[] repetitions; - private final long[] starttime; - private final long[] runtime; - private boolean aborted; - private final List errors = Lists.newLinkedList(); - - public enum Alignment { - LEFT { - @Override - public String pad(String value, int size) { - StringBuilder builder = new StringBuilder(); - builder.append(value == null ? "" : value); - while (builder.length() < size) { - builder.append(" "); - } - return builder.toString(); - } - }, - - RIGHT { - @Override - public String pad(String value, int size) { - String result = (value == null ? "" : value); - while (result.length() < size) { - result = " " + result; - } - return result; - } - }; - - public abstract String pad(String value, int size); - } - - public BenchmarkResult(Benchmark benchmark) { - Preconditions.checkNotNull(benchmark, "Parameter 'benchmark' must not be null"); - this.benchmarkClass = benchmark.getClass(); - this.title = benchmark.getTitle(); - this.repetitions = Preconditions.checkNotNull(benchmark.getRepetitions()); - Preconditions.checkArgument(repetitions.length > 0, "The length of the parameter 'repetitions' has to be greater than zero"); - int reps = repetitions.length; - this.starttime = new long[reps]; - this.runtime = new long[reps]; - } - - public final Iterator> getColumnsIterator() { - return columns.iterator(); - } - - public final void addColumn(Column column) { - columns.add(Preconditions.checkNotNull(column)); - } - - public final int getNumColumns() { - return columns.size(); - } - - public final Class getBenchmarkClass() { - return benchmarkClass; - } - - public final String getTitle() { - return title; - } - - public final int getRepetitions() { - return repetitions.length; - } - - public final int getRepetitions(int rep) { - return repetitions[rep]; - } - - public final long getStartTime(int rep) { - return starttime[rep]; - } - - public final void setStartTime(int rep, long value) { - starttime[rep] = value; - } - - public final long getRunTime(int rep) { - return runtime[rep]; - } - - public final void setRunTime(int rep, long value) { - runtime[rep] = value; - } - - public final boolean isAborted() { - return aborted; - } - - public final Iterator getErrorsIterator() { - return errors.iterator(); - } - - public final int getNumErrors() { - return errors.size(); - } - - public final void addError(BenchmarkError.Type type, Exception error) { - this.aborted = this.aborted || Preconditions.checkNotNull(type).abort; - errors.add(new BenchmarkError(type, error)); - } - - public abstract static class Column { - - public final T owner; - public final Alignment alignment; - public final String name; - - private final int reps; - private final String[] cache; - private boolean hasMaxWidth; - private int maxWidth; - - public Column(T owner, Alignment alignment, String name) { - this.owner = Preconditions.checkNotNull(owner); - this.alignment = Preconditions.checkNotNull(alignment); - this.name = Preconditions.checkNotNull(name); - this.reps = owner.getRepetitions(); - this.cache = new String[reps]; - } - - protected abstract String getValueInternal(int rep); - - public final String getValue(int rep) { - Preconditions.checkElementIndex(rep, reps, "Parameter 'rep'"); - if (cache[rep] == null) { - String v = Preconditions.checkNotNull(getValueInternal(rep), "BenchmarkResult::Column::getValueInternal() must never return null (rep=" + rep + ")"); - cache[rep] = v; - return v; - } - return cache[rep]; - } - - public final int computeMaxWidth() { - if (!hasMaxWidth) { - int max = name.length(); - for (int i = 0; i < reps; i++) { - String v = getValue(i); - if (v.length() > max) { - max = v.length(); - } - } - hasMaxWidth = true; - maxWidth = max; - } - return maxWidth; - } - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/Benchmarks.java b/engine/src/dev/java/org/terasology/benchmark/Benchmarks.java deleted file mode 100644 index a527a9c289c..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/Benchmarks.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -import com.google.common.base.Preconditions; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Benchmarks contains methods to execute one or many benchmarks with support for a progress callback as well as - * a simple pretty printer for benchmark results. - * - */ -public final class Benchmarks { - - private Benchmarks() { - } - - public static BenchmarkResult execute(Benchmark benchmark, int benchmarkIndex, int benchmarkCount, BenchmarkCallback callback) { - - if (callback != null) { - callback.begin(benchmark, benchmarkIndex, benchmarkCount); - } - - final BenchmarkResult result = new BasicBenchmarkResult(benchmark); - final int[] repetitions = Preconditions.checkNotNull(benchmark.getRepetitions(), "Benchmark::getRepetitions() must not return null"); - Preconditions.checkState(repetitions.length > 0, "Benchmark::getRepetitions() must return an array of size greater than zero"); - - try { - benchmark.setup(); - } catch (Exception e) { - result.addError(BenchmarkError.Type.Setup, e); - if (callback != null) { - callback.error(BenchmarkError.Type.Setup, e, result); - } - return result; - } - - try { - if (callback != null) { - callback.warmup(benchmark, false); - } - for (int i = 0; i < benchmark.getWarmupRepetitions(); ++i) { - benchmark.run(); - } - if (callback != null) { - callback.warmup(benchmark, true); - } - } catch (Exception e) { - result.addError(BenchmarkError.Type.Warmup, e); - if (callback != null) { - callback.error(BenchmarkError.Type.Warmup, e, result); - } - return result; - } - - int repsTotal = 0; - int repsSoFar = 0; - for (int reps : repetitions) { - repsTotal += reps; - } - int repsPart = repsTotal / 20; - - int repIndex = 0; - boolean aborted = false; - for (int reps : repetitions) { - - try { - benchmark.prerun(); - } catch (Exception e) { - aborted = true; - result.addError(BenchmarkError.Type.PreRun, e); - if (callback != null) { - callback.error(BenchmarkError.Type.PreRun, e, result); - } - break; - } - - long start = time(); - long elapsed; - try { - result.setStartTime(repIndex, TimeUnit.MILLISECONDS.convert(start, TimeUnit.NANOSECONDS)); - int currentReps = reps; - while (currentReps > repsPart) { - for (int i = 0; i < repsPart; ++i) { - benchmark.run(); - } - currentReps -= repsPart; - repsSoFar += repsPart; - if (callback != null) { - callback.progress(benchmark, 100d / (double) repsTotal * (double) repsSoFar); - } - } - if (currentReps <= repsPart) { - for (int i = 0; i < currentReps; ++i) { - benchmark.run(); - } - repsSoFar += currentReps; - if (callback != null) { - callback.progress(benchmark, 100d / (double) repsTotal * (double) repsSoFar); - } - } - elapsed = elapsed(start, TimeUnit.NANOSECONDS); - result.setRunTime(repIndex, TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.NANOSECONDS)); - } catch (Exception e) { - aborted = true; - result.addError(BenchmarkError.Type.Run, e); - if (callback != null) { - callback.error(BenchmarkError.Type.Run, e, result); - } - break; - } - - try { - benchmark.postrun(); - } catch (Exception e) { - aborted = true; - result.addError(BenchmarkError.Type.PostRun, e); - if (callback != null) { - callback.error(BenchmarkError.Type.PostRun, e, result); - } - break; - } - - ++repIndex; - } - - try { - benchmark.finish(aborted); - } catch (Exception e) { - result.addError(BenchmarkError.Type.Finish, e); - if (callback != null) { - callback.error(BenchmarkError.Type.Finish, e, result); - } - } - - if (callback != null) { - if (result.isAborted()) { - callback.aborted(result); - } else { - callback.success(result); - } - } - - return result; - } - - public static List execute(List benchmarks, BenchmarkCallback callback) { - Preconditions.checkNotNull(benchmarks); - - final List results = new LinkedList<>(); - final int benchmarkCount = benchmarks.size(); - - try { - int benchmarkIndex = 1; - for (Benchmark benchmark : benchmarks) { - Preconditions.checkNotNull(benchmark); - - BenchmarkResult result = execute(benchmark, benchmarkIndex, benchmarkCount, callback); - results.add(result); - - benchmarkIndex++; - } - } catch (Exception e) { - if (callback != null) { - callback.fatal(e); - } - } - - return results; - } - - public static StringBuilder printResults(List results) { - return printResults(results, new StringBuilder()); - } - - - public static StringBuilder printResults(List results, StringBuilder b) { - Preconditions.checkNotNull(b); - final int resultCount = results.size(); - int resultIndex = 1; - for (BenchmarkResult result : results) { - if (resultIndex > 1) { - b.append("\n"); - } - b.append("Benchmark " + resultIndex + " / " + resultCount + ": " + result.getTitle() + "\n"); - printResult(result, b); - resultIndex++; - } - return b; - } - - public static StringBuilder printResult(BenchmarkResult result) { - return printResult(result, new StringBuilder()); - } - - public static StringBuilder printResult(BenchmarkResult result, StringBuilder b) { - Preconditions.checkNotNull(b); - BenchmarkResult.Column[] columns = getColumns(result); - printFieldTitles(result, columns, b); - for (int repIndex = 0; repIndex < result.getRepetitions(); repIndex++) { - printFieldValues(result, repIndex, columns, b); - } - return b; - } - - private static BenchmarkResult.Column[] getColumns(BenchmarkResult result) { - BenchmarkResult.Column[] columns = new BenchmarkResult.Column[result.getNumColumns()]; - Iterator> it = result.getColumnsIterator(); - int i = 0; - while (it.hasNext()) { - columns[i++] = it.next(); - } - return columns; - } - - private static void printFieldTitles(BenchmarkResult result, BenchmarkResult.Column[] columns, StringBuilder b) { - boolean first = true; - for (BenchmarkResult.Column col : columns) { - if (first) { - first = false; - } else { - b.append(" | "); - } - b.append(col.alignment.pad(col.name, col.computeMaxWidth())); - } - b.append("\n"); - } - - private static void printFieldValues(BenchmarkResult result, int repIndex, BenchmarkResult.Column[] columns, StringBuilder b) { - boolean first = true; - for (BenchmarkResult.Column col : columns) { - if (first) { - first = false; - } else { - b.append(" | "); - } - b.append(col.alignment.pad(col.getValue(repIndex), col.computeMaxWidth())); - } - b.append("\n"); - } - - private static long time() { - return System.nanoTime(); - } - - private static long elapsed(long time, TimeUnit unit) { - Preconditions.checkNotNull(unit); - long result = time() - time; - return unit.convert(result, TimeUnit.NANOSECONDS); - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/PrintToConsoleCallback.java b/engine/src/dev/java/org/terasology/benchmark/PrintToConsoleCallback.java deleted file mode 100644 index af02446613e..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/PrintToConsoleCallback.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark; - -import java.text.DecimalFormat; -import java.text.NumberFormat; - -/** - * PrintToConsoleCallback implements BenchmarkCallback and simply prints everything to the console. - * - */ -public class PrintToConsoleCallback implements BenchmarkCallback { - - private static final NumberFormat PERCENT_FORMAT = new DecimalFormat("##0.0"); - - @Override - public void begin(Benchmark benchmark, int benchmarkIndex, int benchmarkCount) { - System.out.println("Benchmark " + benchmarkIndex + " / " + benchmarkCount + ": " + benchmark.getTitle()); - } - - @Override - public void warmup(Benchmark benchmark, boolean finished) { - if (finished) { - System.out.print("Go! "); - } else { - System.out.print("Warmup... "); - } - } - - @Override - public void progress(Benchmark benchmark, double percent) { - System.out.print(PERCENT_FORMAT.format(percent) + "% "); - } - - @Override - public void success(BenchmarkResult result) { - System.out.println(); - System.out.println(); - System.out.println(Benchmarks.printResult(result)); - System.out.println(); - } - - @Override - public void aborted(BenchmarkResult result) { - System.out.println(); - System.out.println("Benchmark aborted: " + result.getTitle()); - System.out.println("Number of errors: " + result.getNumErrors()); - } - - @Override - public void error(BenchmarkError.Type type, Exception e, BenchmarkResult result) { - System.out.println("Benchmark error of type: " + type); - e.printStackTrace(); - } - - @Override - public void fatal(Exception e) { - System.out.println("Fatal benchmark error: " + e.getClass().getSimpleName()); - e.printStackTrace(); - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArray.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArray.java deleted file mode 100644 index a5b13d6db92..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArray.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import com.google.common.base.Preconditions; -import org.terasology.benchmark.Benchmark; -import org.terasology.world.chunks.blockdata.TeraArray; - -/** - * BenchmarkTeraArray is the base class for benchmarking tera arrays. - * - */ -public abstract class BenchmarkTeraArray implements Benchmark { - - protected TeraArray array; - - public BenchmarkTeraArray(TeraArray array) { - this.array = Preconditions.checkNotNull(array); - } - - @Override - public int getWarmupRepetitions() { - return 10000; - } - - @Override - public int[] getRepetitions() { - return new int[]{500, 5000, 50000, 100000}; - } - - @Override - public void setup() { - } - - @Override - public void prerun() { - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java deleted file mode 100644 index e818bf88134..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayDeserializeFromBuffer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; -import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; - -import java.nio.ByteBuffer; - -public class BenchmarkTeraArrayDeserializeFromBuffer extends BenchmarkTeraArraySerialization { - - protected ByteBuffer buffer; - - @SuppressWarnings("rawtypes") - public BenchmarkTeraArrayDeserializeFromBuffer(SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " deserialization from buffer"; - } - - @SuppressWarnings("unchecked") - @Override - public void setup() { - buffer = ByteBuffer.allocate(BUFFER_SIZE); - handler.serialize(array, buffer); - buffer.rewind(); - } - - @Override - public void prerun() { - } - - @Override - public void run() { - handler.deserialize(buffer); - buffer.rewind(); - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayRead.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayRead.java deleted file mode 100644 index 9218b215599..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayRead.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; - -/** - * BenchmarkTeraArrayRead implements a simple read performance benchmark for tera arrays. - * - */ -public class BenchmarkTeraArrayRead extends BenchmarkTeraArray { - - public BenchmarkTeraArrayRead(TeraArray array) { - super(array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " read performance"; - } - - @Override - public void run() { - int tmp = 0; - for (int y = 0; y < array.getSizeY(); y++) { - for (int z = 0; z < array.getSizeZ(); z++) { - for (int x = 0; x < array.getSizeX(); x++) { - tmp += array.get(x, y, z); - array.get(x, y, z); - } - } - } - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java deleted file mode 100644 index 9612cdaa132..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerialization.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import com.google.common.base.Preconditions; -import org.terasology.benchmark.Benchmark; -import org.terasology.world.chunks.blockdata.TeraArray; - -@SuppressWarnings("rawtypes") -public abstract class BenchmarkTeraArraySerialization implements Benchmark { - - public static final int BUFFER_SIZE = 1024 * 1024; - - public final TeraArray.SerializationHandler handler; - public final TeraArray array; - - @SuppressWarnings("unchecked") - public BenchmarkTeraArraySerialization(TeraArray.SerializationHandler handler, TeraArray array) { - this.handler = Preconditions.checkNotNull(handler); - this.array = Preconditions.checkNotNull(array); - Preconditions.checkArgument(handler.canHandle(array.getClass()), "The supplied serialization handler is incompatible to the supplied array"); - } - - @Override - public int getWarmupRepetitions() { - return 10000; - } - - @Override - public int[] getRepetitions() { - return new int[]{1000, 5000, 10000}; - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java deleted file mode 100644 index ceb88b88396..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeObject.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; -import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; - -public class BenchmarkTeraArraySerializeObject extends BenchmarkTeraArraySerialization { - - protected ByteArrayOutputStream out; - - @SuppressWarnings("rawtypes") - public BenchmarkTeraArraySerializeObject(SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " builtin object serialization directly into ByteArrayOutputStream"; - } - - @Override - public void setup() { - out = new ByteArrayOutputStream(BUFFER_SIZE); - } - - @Override - public void prerun() { - } - - @Override - public void run() { - try { - (new ObjectOutputStream(out)).writeObject(array); - out.reset(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java deleted file mode 100644 index 9e1f95ef966..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToBuffer.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; -import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; - -import java.nio.ByteBuffer; - -@SuppressWarnings("rawtypes") -public class BenchmarkTeraArraySerializeToBuffer extends BenchmarkTeraArraySerialization { - - protected ByteBuffer buffer; - - public BenchmarkTeraArraySerializeToBuffer(SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " serialization directly into ByteBuffer"; - } - - @Override - public void setup() { - buffer = ByteBuffer.allocate(BUFFER_SIZE); - } - - @Override - public void prerun() { - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - int bogus = 0; - handler.serialize(array, buffer); - bogus += buffer.position(); - buffer.rewind(); - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToByteString.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToByteString.java deleted file mode 100644 index f70b11fc066..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToByteString.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import com.google.protobuf.ByteString; -import org.terasology.world.chunks.blockdata.TeraArray; -import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; - -import java.nio.ByteBuffer; - -public class BenchmarkTeraArraySerializeToByteString extends BenchmarkTeraArraySerialization { - - protected ByteBuffer buffer; - - @SuppressWarnings("rawtypes") - public BenchmarkTeraArraySerializeToByteString(SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " serialization into ByteString"; - } - - @Override - public void setup() { - buffer = ByteBuffer.allocate(BUFFER_SIZE); - } - - @Override - public void prerun() { - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - handler.serialize(array, buffer); - int length = buffer.position(); - buffer.rewind(); - final ByteString b = ByteString.copyFrom(buffer, length); - buffer.rewind(); - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java deleted file mode 100644 index 7a240bb5a56..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaByteArray.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; -import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; - -public class BenchmarkTeraArraySerializeToStreamViaByteArray extends BenchmarkTeraArraySerialization { - - protected ByteBuffer buffer; - protected ByteArrayOutputStream out; - protected byte[] via; - - @SuppressWarnings("rawtypes") - public BenchmarkTeraArraySerializeToStreamViaByteArray(SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " serialization into ByteBuffer and transfer via byte[] array into ByteArrayOutputStream"; - } - - @Override - public void setup() { - buffer = ByteBuffer.allocate(BUFFER_SIZE); - out = new ByteArrayOutputStream(BUFFER_SIZE); - via = new byte[BUFFER_SIZE]; - } - - @Override - public void prerun() { - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - int bogus = 0; - handler.serialize(array, buffer); - final int length = buffer.position(); - buffer.rewind(); - buffer.get(via, 0, length); - buffer.rewind(); - out.write(via, 0, length); - out.reset(); - bogus += length; - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java deleted file mode 100644 index 6c57f3e24a9..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArraySerializeToStreamViaChannel.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.WritableByteChannel; - -public class BenchmarkTeraArraySerializeToStreamViaChannel extends BenchmarkTeraArraySerialization { - - protected ByteBuffer buffer; - protected ByteArrayOutputStream out; - protected WritableByteChannel channel; - - @SuppressWarnings("rawtypes") - public BenchmarkTeraArraySerializeToStreamViaChannel(TeraArray.SerializationHandler handler, TeraArray array) { - super(handler, array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " serialization into ByteBuffer and transfer via Channel into ByteArrayOutputStream"; - } - - @Override - public void setup() { - buffer = ByteBuffer.allocate(BUFFER_SIZE); - out = new ByteArrayOutputStream(BUFFER_SIZE); - channel = Channels.newChannel(out); - } - - @Override - public void prerun() { - } - - @SuppressWarnings("unchecked") - @Override - public void run() { - try { - handler.serialize(array, buffer); - buffer.rewind(); - channel.write(buffer); - buffer.rewind(); - out.reset(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void postrun() { - } - - @Override - public void finish(boolean aborted) { - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayWrite.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayWrite.java deleted file mode 100644 index 93ff6456d9f..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/BenchmarkTeraArrayWrite.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.world.chunks.blockdata.TeraArray; - -/** - * BenchmarkTeraArrayWrite implements a simple write performance benchmark for tera arrays. - * - */ -public class BenchmarkTeraArrayWrite extends BenchmarkTeraArray { - - public BenchmarkTeraArrayWrite(TeraArray array) { - super(array); - } - - @Override - public String getTitle() { - return array.getClass().getSimpleName() + " write performance"; - } - - @Override - public void run() { - for (int y = 0; y < array.getSizeY(); y++) { - for (int z = 0; z < array.getSizeZ(); z++) { - for (int x = 0; x < array.getSizeX(); x++) { - array.set(x, y, z, 1); - } - } - } - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java deleted file mode 100644 index 51fab7e7dec..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/arrays/TeraArraysBenchmark.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.arrays; - -import org.terasology.benchmark.Benchmarks; -import org.terasology.benchmark.Benchmark; -import org.terasology.benchmark.PrintToConsoleCallback; -import org.terasology.world.chunks.blockdata.TeraDenseArray8Bit; - -import java.util.LinkedList; -import java.util.List; - -/** - * TeraArraysBenchmark simplifies the execution of the benchmarks for tera arrays. - * - */ -@SuppressWarnings("unused") -public final class TeraArraysBenchmark { - - private static final byte[][] INFLATED_8_BIT = new byte[256][]; - private static final byte[] DEFLATED_8_BIT = new byte[256]; - - private static final byte[][] INFLATED_4_BIT = new byte[256][]; - private static final byte[] DEFLATED_4_BIT = new byte[256]; - - static { - for (int i = 0; i < INFLATED_8_BIT.length; i++) { - INFLATED_8_BIT[i] = new byte[256]; - } - for (int i = 0; i < INFLATED_4_BIT.length; i++) { - INFLATED_4_BIT[i] = new byte[128]; - } - } - - private TeraArraysBenchmark() { - } - - public static void main(String[] args) { - - final List benchmarks = new LinkedList<>(); - - benchmarks.add(new BenchmarkTeraArraySerializeObject(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); - benchmarks.add(new BenchmarkTeraArraySerializeToBuffer(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); - benchmarks.add(new BenchmarkTeraArraySerializeToByteString(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); - benchmarks.add(new BenchmarkTeraArraySerializeToStreamViaByteArray(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); - benchmarks.add(new BenchmarkTeraArraySerializeToStreamViaChannel(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); - -// benchmarks.add(new BenchmarkTeraArrayDeserializeFromBuffer(new TeraDenseArray8Bit.SerializationHandler(), new TeraDenseArray8Bit(16, 256, 16))); -// -// -// benchmarks.add(new BenchmarkTeraArrayRead(new TeraDenseArray8Bit(16, 256, 16))); -// benchmarks.add(new BenchmarkTeraArrayRead(new TeraDenseArray4Bit(16, 256, 16))); -// benchmarks.add(new BenchmarkTeraArrayRead(new TeraSparseArray8Bit(16, 256, 16, INFLATED_8_BIT, DEFLATED_8_BIT))); -// benchmarks.add(new BenchmarkTeraArrayRead(new TeraSparseArray4Bit(16, 256, 16, INFLATED_4_BIT, DEFLATED_4_BIT))); -// -// -// benchmarks.add(new BenchmarkTeraArrayWrite(new TeraDenseArray8Bit(16, 256, 16))); -// benchmarks.add(new BenchmarkTeraArrayWrite(new TeraDenseArray4Bit(16, 256, 16))); -// benchmarks.add(new BenchmarkTeraArrayWrite(new TeraSparseArray8Bit(16, 256, 16, INFLATED_8_BIT, DEFLATED_8_BIT))); -// benchmarks.add(new BenchmarkTeraArrayWrite(new TeraSparseArray4Bit(16, 256, 16, INFLATED_4_BIT, DEFLATED_4_BIT))); - - Benchmarks.execute(benchmarks, new PrintToConsoleCallback()); - - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/cache/BenchmarkChunkCache.java b/engine/src/dev/java/org/terasology/benchmark/chunks/cache/BenchmarkChunkCache.java deleted file mode 100644 index 4a4281fe386..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/cache/BenchmarkChunkCache.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.cache; - -import org.terasology.benchmark.Benchmark; - -public class BenchmarkChunkCache implements Benchmark { - - public BenchmarkChunkCache() { - } - - @Override - public String getTitle() { - return null; - } - - @Override - public int getWarmupRepetitions() { - return 1; - } - - @Override - public int[] getRepetitions() { - return new int[]{1, 10}; - } - - @Override - public void setup() { - - } - - @Override - public void prerun() { - - } - - @Override - public void run() { - } - - @Override - public void postrun() { - - } - - @Override - public void finish(boolean aborted) { - - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/chunks/cache/ChunkCachesBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/chunks/cache/ChunkCachesBenchmark.java deleted file mode 100644 index cc0fcf53270..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/chunks/cache/ChunkCachesBenchmark.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.chunks.cache; - -public final class ChunkCachesBenchmark { - - private ChunkCachesBenchmark() { - } - - public static void main(String[] args) { - - } - -} diff --git a/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java deleted file mode 100644 index f0c06427198..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.entitySystem; - -import com.google.common.collect.Lists; -import org.terasology.benchmark.AbstractBenchmark; -import org.terasology.entitySystem.Component; -import org.terasology.entitySystem.entity.internal.PojoEntityManager; -import org.terasology.logic.location.LocationComponent; -import org.terasology.rendering.logic.MeshComponent; -import org.terasology.utilities.random.FastRandom; -import org.terasology.world.block.BlockComponent; - -import java.util.List; - -public class EntityCreateBenchmark extends AbstractBenchmark { - - private List> rawEntityData; - - public EntityCreateBenchmark() { - super("Create Entities", 10000, new int[]{10000}); - } - - @Override - public void setup() { - FastRandom rand = new FastRandom(0L); - rawEntityData = Lists.newArrayList(); - for (int i = 0; i < 1000; ++i) { - List entityData = Lists.newArrayList(); - if (rand.nextFloat() < 0.75f) { - entityData.add(new LocationComponent()); - } - if (rand.nextFloat() < 0.5f) { - entityData.add(new MeshComponent()); - } - if (rand.nextFloat() < 0.25f) { - entityData.add(new BlockComponent()); - } - rawEntityData.add(entityData); - } - } - - @Override - public void run() { - PojoEntityManager entityManager = new PojoEntityManager(); - rawEntityData.forEach(entityManager::create); - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntitySystemBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntitySystemBenchmark.java deleted file mode 100644 index 348d03a9915..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/entitySystem/EntitySystemBenchmark.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.entitySystem; - -import com.google.common.collect.Lists; -import org.terasology.benchmark.Benchmarks; -import org.terasology.benchmark.PrintToConsoleCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.benchmark.Benchmark; - -import java.util.List; - -/** - * - */ -public final class EntitySystemBenchmark { - private static final Logger logger = LoggerFactory.getLogger(EntitySystemBenchmark.class); - - private EntitySystemBenchmark() { - } - - public static void main(String[] args) { - final List benchmarks = Lists.newArrayList(); - - benchmarks.add(new EntityCreateBenchmark()); - benchmarks.add(new IterateSingleComponentBenchmark()); - benchmarks.add(new IterateMultipleComponentBenchmark()); - Benchmarks.execute(benchmarks, new PrintToConsoleCallback()); - - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateMultipleComponentBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateMultipleComponentBenchmark.java deleted file mode 100644 index be8f64f6f02..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateMultipleComponentBenchmark.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.entitySystem; - -import com.google.common.collect.Lists; -import org.terasology.benchmark.AbstractBenchmark; -import org.terasology.entitySystem.Component; -import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.entitySystem.entity.internal.PojoEntityManager; -import org.terasology.logic.location.LocationComponent; -import org.terasology.rendering.logic.MeshComponent; -import org.terasology.utilities.random.FastRandom; -import org.terasology.world.block.BlockComponent; - -import java.util.List; - -/** - * - */ -public class IterateMultipleComponentBenchmark extends AbstractBenchmark { - - private List> rawEntityData; - private PojoEntityManager entityManager; - - public IterateMultipleComponentBenchmark() { - super("Iterate entities by multiple components", 10000, new int[]{10000}); - } - - @Override - public void setup() { - FastRandom rand = new FastRandom(0L); - rawEntityData = Lists.newArrayList(); - for (int i = 0; i < 1000; ++i) { - List entityData = Lists.newArrayList(); - if (rand.nextFloat() < 0.75f) { - entityData.add(new LocationComponent()); - } - if (rand.nextFloat() < 0.5f) { - entityData.add(new MeshComponent()); - } - if (rand.nextFloat() < 0.25f) { - entityData.add(new BlockComponent()); - } - rawEntityData.add(entityData); - } - - entityManager = new PojoEntityManager(); - for (List rawEntity : rawEntityData) { - entityManager.create(rawEntity); - } - } - - @Override - public void run() { - for (EntityRef entity : entityManager.getEntitiesWith(MeshComponent.class, LocationComponent.class)) { - LocationComponent loc = entity.getComponent(LocationComponent.class); - MeshComponent meshComp = entity.getComponent(MeshComponent.class); - loc.getLocalPosition(); - } - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateSingleComponentBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateSingleComponentBenchmark.java deleted file mode 100644 index a6920350447..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/entitySystem/IterateSingleComponentBenchmark.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.entitySystem; - -import com.google.common.collect.Lists; -import org.terasology.benchmark.AbstractBenchmark; -import org.terasology.entitySystem.Component; -import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.entitySystem.entity.internal.PojoEntityManager; -import org.terasology.logic.location.LocationComponent; -import org.terasology.rendering.logic.MeshComponent; -import org.terasology.utilities.random.FastRandom; -import org.terasology.world.block.BlockComponent; - -import java.util.List; - -/** - * - */ -public class IterateSingleComponentBenchmark extends AbstractBenchmark { - private List> rawEntityData; - private PojoEntityManager entityManager; - - public IterateSingleComponentBenchmark() { - super("Iterate Entities Single Component", 10000, new int[]{10000}); - } - - @Override - public void setup() { - FastRandom rand = new FastRandom(0L); - rawEntityData = Lists.newArrayList(); - for (int i = 0; i < 1000; ++i) { - List entityData = Lists.newArrayList(); - if (rand.nextFloat() < 0.75f) { - entityData.add(new LocationComponent()); - } - if (rand.nextFloat() < 0.5f) { - entityData.add(new MeshComponent()); - } - if (rand.nextFloat() < 0.25f) { - entityData.add(new BlockComponent()); - } - rawEntityData.add(entityData); - } - - entityManager = new PojoEntityManager(); - for (List rawEntity : rawEntityData) { - entityManager.create(rawEntity); - } - } - - @Override - public void run() { - for (EntityRef entity : entityManager.getEntitiesWith(LocationComponent.class)) { - LocationComponent loc = entity.getComponent(LocationComponent.class); - loc.getLocalPosition(); - } - } - - @Override - public void finish(boolean aborted) { - rawEntityData = null; - entityManager = null; - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ConstructionBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ConstructionBenchmark.java deleted file mode 100644 index 3b7030bfd64..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ConstructionBenchmark.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.reflectFactory; - -import org.terasology.benchmark.AbstractBenchmark; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.reflection.reflect.ObjectConstructor; -import org.terasology.reflection.reflect.ReflectFactory; -import org.terasology.logic.location.LocationComponent; - -/** - * - */ -public class ConstructionBenchmark extends AbstractBenchmark { - - private static final Logger logger = LoggerFactory.getLogger(ConstructionBenchmark.class); - private ReflectFactory reflectFactory; - private ObjectConstructor constructor; - - public ConstructionBenchmark(ReflectFactory reflectFactory) { - super("Construction via " + reflectFactory.getClass().getSimpleName(), 100000000, new int[]{100000000, 100000000}); - this.reflectFactory = reflectFactory; - } - - @Override - public void setup() { - try { - constructor = reflectFactory.createConstructor(LocationComponent.class); - } catch (NoSuchMethodException e) { - logger.error("Failed to establish constructor object", e); - } - } - - @Override - public void run() { - constructor.construct(); - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/FieldAccessBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/reflectFactory/FieldAccessBenchmark.java deleted file mode 100644 index 901e8a00c7c..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/FieldAccessBenchmark.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.reflectFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.benchmark.AbstractBenchmark; -import org.terasology.logic.common.DisplayNameComponent; -import org.terasology.reflection.reflect.FieldAccessor; -import org.terasology.reflection.reflect.InaccessibleFieldException; -import org.terasology.reflection.reflect.ReflectFactory; - -/** - */ -public class FieldAccessBenchmark extends AbstractBenchmark { - - private static final Logger logger = LoggerFactory.getLogger(ConstructionBenchmark.class); - private ReflectFactory reflectFactory; - private FieldAccessor accessor; - private int i; - private DisplayNameComponent comp; - - public FieldAccessBenchmark(ReflectFactory reflectFactory) { - super("Field access via " + reflectFactory.getClass().getSimpleName(), 100000000, new int[]{100000000, 100000000}); - this.reflectFactory = reflectFactory; - } - - @Override - public void setup() { - i = 0; - comp = new DisplayNameComponent(); - try { - accessor = reflectFactory.createFieldAccessor(DisplayNameComponent.class, DisplayNameComponent.class.getField("description")); - } catch (InaccessibleFieldException | NoSuchFieldException e) { - logger.error("Failed to establish field accessor object", e); - } - } - - @Override - public void run() { - accessor.setValue(comp, i++); - int val = (int) accessor.getValue(comp); - val++; - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterAccessBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterAccessBenchmark.java deleted file mode 100644 index ac94997ed52..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterAccessBenchmark.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.benchmark.reflectFactory; - -import org.terasology.benchmark.AbstractBenchmark; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.reflection.reflect.FieldAccessor; -import org.terasology.reflection.reflect.InaccessibleFieldException; -import org.terasology.reflection.reflect.ReflectFactory; - -/** - */ -public class GetterSetterAccessBenchmark extends AbstractBenchmark { - - private static final Logger logger = LoggerFactory.getLogger(ConstructionBenchmark.class); - private ReflectFactory reflectFactory; - private FieldAccessor accessor; - private int i; - private GetterSetterComponent comp; - - public GetterSetterAccessBenchmark(ReflectFactory reflectFactory) { - super("Getter/Setter access via " + reflectFactory.getClass().getSimpleName(), 100000000, new int[]{100000000, 100000000}); - this.reflectFactory = reflectFactory; - } - - @Override - public void setup() { - i = 0; - comp = new GetterSetterComponent(); - try { - accessor = reflectFactory.createFieldAccessor(GetterSetterComponent.class, GetterSetterComponent.class.getDeclaredField("value")); - } catch (InaccessibleFieldException | NoSuchFieldException e) { - logger.error("Failed to establish field accessor object", e); - } - } - - @Override - public void run() { - accessor.setValue(comp, i++); - int val = (int) accessor.getValue(comp); - val++; - } -} diff --git a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ReflectFactoryBenchmark.java b/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ReflectFactoryBenchmark.java deleted file mode 100644 index 22b6d8fb546..00000000000 --- a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/ReflectFactoryBenchmark.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.benchmark.reflectFactory; - -import com.google.common.collect.Lists; -import org.terasology.benchmark.Benchmarks; -import org.terasology.benchmark.PrintToConsoleCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.benchmark.Benchmark; -import org.terasology.reflection.reflect.ByteCodeReflectFactory; -import org.terasology.reflection.reflect.ReflectionReflectFactory; - -import java.util.List; - -/** - * - */ -public final class ReflectFactoryBenchmark { - private static final Logger logger = LoggerFactory.getLogger(ReflectFactoryBenchmark.class); - - private ReflectFactoryBenchmark() { - } - - public static void main(String[] args) { - final List benchmarks = Lists.newArrayList(); - - benchmarks.add(new FieldAccessBenchmark(new ReflectionReflectFactory())); - benchmarks.add(new FieldAccessBenchmark(new ByteCodeReflectFactory())); - benchmarks.add(new GetterSetterAccessBenchmark(new ReflectionReflectFactory())); - benchmarks.add(new GetterSetterAccessBenchmark(new ByteCodeReflectFactory())); - benchmarks.add(new ConstructionBenchmark(new ReflectionReflectFactory())); - benchmarks.add(new ConstructionBenchmark(new ByteCodeReflectFactory())); - - Benchmarks.execute(benchmarks, new PrintToConsoleCallback()); - - } -} diff --git a/engine/src/jmh/java/org/terasology/benchmark/chunks/arrays/TeraArrayBenchmark.java b/engine/src/jmh/java/org/terasology/benchmark/chunks/arrays/TeraArrayBenchmark.java new file mode 100644 index 00000000000..8d69d989403 --- /dev/null +++ b/engine/src/jmh/java/org/terasology/benchmark/chunks/arrays/TeraArrayBenchmark.java @@ -0,0 +1,158 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.benchmark.chunks.arrays; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.terasology.world.chunks.blockdata.TeraArray; +import org.terasology.world.chunks.blockdata.TeraArray.SerializationHandler; +import org.terasology.world.chunks.blockdata.TeraDenseArray16Bit; +import org.terasology.world.chunks.blockdata.TeraDenseArray4Bit; +import org.terasology.world.chunks.blockdata.TeraDenseArray8Bit; +import org.terasology.world.chunks.blockdata.TeraSparseArray4Bit; +import org.terasology.world.chunks.blockdata.TeraSparseArray8Bit; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1) +@Fork(1) +@Measurement(iterations = 1) +public class TeraArrayBenchmark { + + public static final int BUFFER_SIZE = 1024 * 1024; + + private static final byte[][] INFLATED_8_BIT = new byte[256][]; + private static final byte[] DEFLATED_8_BIT = new byte[256]; + + private static final byte[][] INFLATED_4_BIT = new byte[256][]; + private static final byte[] DEFLATED_4_BIT = new byte[256]; + + static { + for (int i = 0; i < INFLATED_8_BIT.length; i++) { + INFLATED_8_BIT[i] = new byte[256]; + } + for (int i = 0; i < INFLATED_4_BIT.length; i++) { + INFLATED_4_BIT[i] = new byte[128]; + } + } + + + @Benchmark + public int fullyRead(ArrayState state) { + int tmp = 0; + for (int y = 0; y < state.array.getSizeY(); y++) { + for (int z = 0; z < state.array.getSizeZ(); z++) { + for (int x = 0; x < state.array.getSizeX(); x++) { + tmp += state.array.get(x, y, z); + } + } + } + return tmp; + } + + @Benchmark + public void fullyWrite(ArrayState state) { + for (int y = 0; y < state.array.getSizeY(); y++) { + for (int z = 0; z < state.array.getSizeZ(); z++) { + for (int x = 0; x < state.array.getSizeX(); x++) { + state.array.set(x, y, z, 1); + } + } + } + } + + @Benchmark + public ByteBuffer toByteBuffer(ArrayState state, ByteBufferState bbState) { + return state.handler.serialize(state.array, bbState.out); + } + + @Benchmark + public TeraArray fromByteBuffer(ArrayState state, FilledByteBufferState bbState) { + return state.handler.deserialize(bbState.in); + } + + + public enum TeraArrayType { + DENCE_4BIT(() -> new TeraDenseArray4Bit(16, 256, 16), TeraDenseArray4Bit.SerializationHandler::new), + DENCE_8BIT(() -> new TeraDenseArray8Bit(16, 256, 16), TeraDenseArray8Bit.SerializationHandler::new), + DENCE_16BIT(() -> new TeraDenseArray16Bit(16, 256, 16), TeraDenseArray16Bit.SerializationHandler::new), + SPARCE_4BIT(() -> new TeraSparseArray4Bit(16, 256, 16, INFLATED_4_BIT, DEFLATED_4_BIT), + TeraSparseArray4Bit.SerializationHandler::new), + SPARCE_8BIT(() -> new TeraSparseArray8Bit(16, 256, 16, INFLATED_8_BIT, DEFLATED_8_BIT), + TeraSparseArray8Bit.SerializationHandler::new), + ; + + private final Supplier creator; + private final Supplier handler; + + TeraArrayType(Supplier creator, Supplier handler) { + this.creator = creator; + this.handler = handler; + } + + public TeraArray create() { + return creator.get(); + } + + public SerializationHandler handler() { + return handler.get(); + } + } + + + @State(Scope.Thread) + public static class ByteBufferState { + private ByteBuffer out; + + @Setup(Level.Invocation) + public void setup() throws IOException { + out = ByteBuffer.allocate(BUFFER_SIZE); + } + + } + + @State(Scope.Thread) + public static class FilledByteBufferState { + private ByteBuffer in; + + @Setup(Level.Invocation) + public void setup(ArrayState arrayState) { + in = ByteBuffer.allocate(BUFFER_SIZE); + arrayState.handler.serialize(arrayState.array, in); + in.rewind(); + } + + } + + @State(Scope.Thread) + public static class ArrayState { + @Param({"DENCE_4BIT", "DENCE_8BIT", "DENCE_16BIT", "SPARCE_4BIT", "SPARCE_8BIT"}) + private static TeraArrayType arrayType; + + private SerializationHandler handler; + private TeraArray array; + + @Setup + public void setup() { + array = arrayType.create(); + handler = arrayType.handler(); + } + } + +} diff --git a/engine/src/jmh/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java b/engine/src/jmh/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java new file mode 100644 index 00000000000..1ab1be68d6a --- /dev/null +++ b/engine/src/jmh/java/org/terasology/benchmark/entitySystem/EntityCreateBenchmark.java @@ -0,0 +1,61 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.benchmark.entitySystem; + +import com.google.common.collect.Lists; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.terasology.entitySystem.Component; +import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.entitySystem.entity.internal.PojoEntityManager; +import org.terasology.logic.location.LocationComponent; +import org.terasology.rendering.logic.MeshComponent; +import org.terasology.utilities.random.FastRandom; +import org.terasology.world.block.BlockComponent; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1) +@Measurement(iterations = 1) +public class EntityCreateBenchmark { + + @Benchmark + public EntityRef createEntity(StateObject state) { + return state.entityManager.create(state.entityData); + } + + @State(Scope.Thread) + public static class StateObject { + + private List entityData; + private PojoEntityManager entityManager; + + @Setup(Level.Invocation) + public void setup() { + entityData = Lists.newArrayList(); + entityManager = new PojoEntityManager(); + FastRandom rand = new FastRandom(0L); + if (rand.nextFloat() < 0.75f) { + entityData.add(new LocationComponent()); + } + if (rand.nextFloat() < 0.5f) { + entityData.add(new MeshComponent()); + } + if (rand.nextFloat() < 0.25f) { + entityData.add(new BlockComponent()); + } + } + } +} diff --git a/engine/src/jmh/java/org/terasology/benchmark/entitySystem/IterateComponentsBenchmark.java b/engine/src/jmh/java/org/terasology/benchmark/entitySystem/IterateComponentsBenchmark.java new file mode 100644 index 00000000000..28e3bfd315d --- /dev/null +++ b/engine/src/jmh/java/org/terasology/benchmark/entitySystem/IterateComponentsBenchmark.java @@ -0,0 +1,71 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.benchmark.entitySystem; + +import com.google.common.collect.Lists; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.terasology.entitySystem.Component; +import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.entitySystem.entity.internal.PojoEntityManager; +import org.terasology.logic.location.LocationComponent; +import org.terasology.rendering.logic.MeshComponent; +import org.terasology.utilities.random.FastRandom; +import org.terasology.world.block.BlockComponent; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1) +@Measurement(iterations = 1) +public class IterateComponentsBenchmark { + + @State(Scope.Benchmark) + public static class StateObject { + private final PojoEntityManager entityManager = new PojoEntityManager(); + + public void setup() { + FastRandom rand = new FastRandom(0L); + for (int i = 0; i < 1000; ++i) { + List entityData = Lists.newArrayList(); + if (rand.nextFloat() < 0.75f) { + entityData.add(new LocationComponent()); + } + if (rand.nextFloat() < 0.5f) { + entityData.add(new MeshComponent()); + } + if (rand.nextFloat() < 0.25f) { + entityData.add(new BlockComponent()); + } + entityManager.create(entityData); + } + } + } + + @Benchmark + public void iterateMultipleComponent(StateObject state) { + for (EntityRef entity : state.entityManager.getEntitiesWith(MeshComponent.class, LocationComponent.class)) { + LocationComponent loc = entity.getComponent(LocationComponent.class); + MeshComponent meshComp = entity.getComponent(MeshComponent.class); + loc.getLocalPosition(); + } + } + + @Benchmark + public void iterateSingleComponent(StateObject state) { + for (EntityRef entity : state.entityManager.getEntitiesWith(LocationComponent.class)) { + LocationComponent loc = entity.getComponent(LocationComponent.class); + loc.getLocalPosition(); + } + } + +} diff --git a/engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterComponent.java b/engine/src/jmh/java/org/terasology/benchmark/reflectFactory/GetterSetterComponent.java similarity index 100% rename from engine/src/dev/java/org/terasology/benchmark/reflectFactory/GetterSetterComponent.java rename to engine/src/jmh/java/org/terasology/benchmark/reflectFactory/GetterSetterComponent.java diff --git a/engine/src/jmh/java/org/terasology/benchmark/reflectFactory/ReflectionFactoryBenchmark.java b/engine/src/jmh/java/org/terasology/benchmark/reflectFactory/ReflectionFactoryBenchmark.java new file mode 100644 index 00000000000..a62d8dfd2c1 --- /dev/null +++ b/engine/src/jmh/java/org/terasology/benchmark/reflectFactory/ReflectionFactoryBenchmark.java @@ -0,0 +1,174 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.benchmark.reflectFactory; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.terasology.logic.common.DisplayNameComponent; +import org.terasology.logic.location.LocationComponent; +import org.terasology.reflection.reflect.ByteCodeReflectFactory; +import org.terasology.reflection.reflect.FieldAccessor; +import org.terasology.reflection.reflect.ObjectConstructor; +import org.terasology.reflection.reflect.ReflectFactory; +import org.terasology.reflection.reflect.ReflectionReflectFactory; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1) +@Measurement(iterations = 1) +public class ReflectionFactoryBenchmark { + + @Benchmark + public Object byteCodeConstructor(ByteCodeState state) { + return state.constructor.construct(); + } + + @Benchmark + public Object reflectionConstructor(ReflectionState state) { + return state.constructor.construct(); + } + + @Benchmark + public Object byteCodeFieldAccessGet(ByteCodeState state, FieldComponentState fieldComponentState) { + return state.fieldAccessor.getValue(fieldComponentState.component); + } + + @Benchmark + public Object reflectionFieldAccessGet(ReflectionState state, FieldComponentState fieldComponentState) { + return state.fieldAccessor.getValue(fieldComponentState.component); + } + + @Benchmark + public void byteCodeFieldAccessSet(ByteCodeState state, FieldComponentState fieldComponentState) { + state.fieldAccessor.setValue(fieldComponentState.component, fieldComponentState.value); + } + + @Benchmark + public void reflectionFieldAccessSet(ReflectionState state, FieldComponentState fieldComponentState) { + state.fieldAccessor.setValue(fieldComponentState.component, fieldComponentState.value); + } + + @Benchmark + public Object byteCodeGetterSetterAccessGet(ByteCodeState state, + GetterSetterComponentState getterSetterComponentState) { + return state.getterSetterAccessor.getValue(getterSetterComponentState.component); + } + + @Benchmark + public Object reflectionGetterSetterAccessGet(ReflectionState state, + GetterSetterComponentState getterSetterComponentState) { + return state.getterSetterAccessor.getValue(getterSetterComponentState.component); + } + + + @Benchmark + public void byteCodeGetterSetterAccessSet(ByteCodeState state, + GetterSetterComponentState getterSetterComponentState) { + state.getterSetterAccessor.setValue(getterSetterComponentState.component, getterSetterComponentState.value); + } + + @Benchmark + public void reflectionGetterSetterAccessSet(ReflectionState state, + GetterSetterComponentState getterSetterComponentState) { + state.getterSetterAccessor.setValue(getterSetterComponentState.component, getterSetterComponentState.value); + } + + + @Benchmark + public void directGetterSetterSet(GetterSetterComponentState getterSetterComponentState) { + getterSetterComponentState.component.setValue(getterSetterComponentState.value); + } + + @Benchmark + public Object directGetterSetterGet(GetterSetterComponentState getterSetterComponentState) { + return getterSetterComponentState.component.getValue(); + } + + @Benchmark + public void directFieldSet(FieldComponentState state) { + state.component.name = state.value; + } + + @Benchmark + public Object directFieldGet(FieldComponentState state) { + return state.component.name; + } + + @Benchmark + public Object directConstructor() { + return new LocationComponent(); + } + + @State(Scope.Thread) + public static class GetterSetterComponentState { + private GetterSetterComponent component; + private int value; + + @Setup + public void setup() { + component = new GetterSetterComponent(); + component.setValue(1); + value = 90; + } + } + + @State(Scope.Thread) + public static class FieldComponentState { + private DisplayNameComponent component; + private String value; + + @Setup + public void setup() { + component = new DisplayNameComponent(); + component.name = "dummy"; + value = "dummy1"; + } + } + + + @State(Scope.Thread) + public static class ByteCodeState extends StateObject { + + @Override + ReflectFactory getReflectFactory() { + return new ByteCodeReflectFactory(); + } + } + + @State(Scope.Thread) + public static class ReflectionState extends StateObject { + + @Override + ReflectFactory getReflectFactory() { + return new ReflectionReflectFactory(); + } + } + + public abstract static class StateObject { + ObjectConstructor constructor; + FieldAccessor fieldAccessor; + FieldAccessor getterSetterAccessor; + + @Setup + public void setup() throws Exception { + ReflectFactory reflectFactory = getReflectFactory(); + constructor = reflectFactory.createConstructor(LocationComponent.class); + fieldAccessor = reflectFactory.createFieldAccessor(DisplayNameComponent.class, + DisplayNameComponent.class.getField("description")); + getterSetterAccessor = reflectFactory.createFieldAccessor(GetterSetterComponent.class, + GetterSetterComponent.class.getDeclaredField("value")); + } + + abstract ReflectFactory getReflectFactory(); + } +} From 224f8adb12f48e0ef1b3faf5a53420cbec443095 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Wed, 13 Jan 2021 22:00:03 +0100 Subject: [PATCH 115/259] feat(JOML): migrate `BatchPropagator` (#4395) * feat(JOML): migrate `InternalLightProcessor` * feat(JOML): migrate `SunlightRegenBatchPropagator` * refactor: remove duplicate code * refactor: move `populateMinAdjacent2D` from `ChunkMath` to `BatchPropagator` * chore!: remove deprecated methods from `BatchPropagator` Follow up to #4391 --- .../java/org/terasology/math/ChunkMath.java | 53 +-------------- .../world/propagation/BatchPropagator.java | 64 ++++++++++++++----- .../propagation/StandardBatchPropagator.java | 2 +- .../SunlightRegenBatchPropagator.java | 35 ++++------ .../light/InternalLightProcessor.java | 8 ++- 5 files changed, 67 insertions(+), 95 deletions(-) diff --git a/engine/src/main/java/org/terasology/math/ChunkMath.java b/engine/src/main/java/org/terasology/math/ChunkMath.java index 14722f0fdc8..5c9fb5cb322 100644 --- a/engine/src/main/java/org/terasology/math/ChunkMath.java +++ b/engine/src/main/java/org/terasology/math/ChunkMath.java @@ -490,7 +490,7 @@ public static Region3i getChunkRegionAroundWorldPos(Vector3i pos, int extent) { * @param extent the extent * @return chunk region * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link org.terasology.world.chunks.Chunks#toChunkRegion(BlockRegion, BlockRegion)}. + * method will be replaced with JOML implementation {@link org.terasology.world.chunks.Chunks#toChunkRegion(BlockRegionc, BlockRegion)}. * */ @Deprecated @@ -641,57 +641,6 @@ public static BlockRegion getEdgeRegion(BlockRegionc region, Side side, BlockReg } } - /** - * Populates a target array with the minimum value adjacent to each location, including the location itself. TODO: - * this is too specific for a general class like this. Move to a new class AbstractBatchPropagator - * - * @param source - * @param target - * @param populateMargins Whether to populate the edges of the target array - */ - public static void populateMinAdjacent2D(int[] source, int[] target, int dimX, int dimY, boolean populateMargins) { - System.arraycopy(source, 0, target, 0, target.length); - - // 0 < x < dimX - 1; 0 < y < dimY - 1 - for (int y = 1; y < dimY - 1; ++y) { - for (int x = 1; x < dimX - 1; ++x) { - target[x + y * dimX] = Math.min(Math.min(source[x + (y - 1) * dimX], source[x + (y + 1) * dimX]), - Math.min(source[x + 1 + y * dimX], source[x - 1 + y * dimX])); - } - } - - if (populateMargins) { - // x == 0, y == 0 - target[0] = Math.min(source[1], source[dimX]); - - // 0 < x < dimX - 1, y == 0 - for (int x = 1; x < dimX - 1; ++x) { - target[x] = Math.min(source[x - 1], Math.min(source[x + 1], source[x + dimX])); - } - - // x == dimX - 1, y == 0 - target[dimX - 1] = Math.min(source[2 * dimX - 1], source[dimX - 2]); - - // 0 < y < dimY - 1 - for (int y = 1; y < dimY - 1; ++y) { - // x == 0 - target[y * dimX] = Math.min(source[dimX * (y - 1)], Math.min(source[dimX * (y + 1)], source[1 + dimX * y])); - // x == dimX - 1 - target[dimX - 1 + y * dimX] = Math.min(source[dimX - 1 + dimX * (y - 1)], Math.min(source[dimX - 1 + dimX * (y + 1)], source[dimX - 2 + dimX * y])); - } - // x == 0, y == dimY - 1 - target[dimX * (dimY - 1)] = Math.min(source[1 + dimX * (dimY - 1)], source[dimX * (dimY - 2)]); - - // 0 < x < dimX - 1; y == dimY - 1 - for (int x = 1; x < dimX - 1; ++x) { - target[x + dimX * (dimY - 1)] = Math.min(source[x - 1 + dimX * (dimY - 1)], Math.min(source[x + 1 + dimX * (dimY - 1)], source[x + dimX * (dimY - 2)])); - } - - // x == dimX - 1; y == dimY - 1 - target[dimX - 1 + dimX * (dimY - 1)] = Math.min(source[dimX - 2 + dimX * (dimY - 1)], source[dimX - 1 + dimX * (dimY - 2)]); - } - } - /** * Works out whether the given block resides inside the given chunk. *

diff --git a/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java index de98f150573..b1b84614469 100644 --- a/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/BatchPropagator.java @@ -2,10 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; +import org.joml.Math; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.chunks.LitChunk; @@ -46,11 +45,6 @@ public interface BatchPropagator { */ void propagateFrom(Vector3ic pos, Block block); - @Deprecated - default void propagateFrom(Vector3i pos, Block block) { - propagateFrom(JomlUtil.from(pos), block); - }; - /** * Propagates a specific value out from a location * @@ -59,11 +53,6 @@ default void propagateFrom(Vector3i pos, Block block) { */ void propagateFrom(Vector3ic pos, byte value); - @Deprecated - default void propagateFrom(Vector3i pos, byte value) { - propagateFrom(JomlUtil.from(pos), value); - } - /** * TODO: Document * @@ -72,8 +61,53 @@ default void propagateFrom(Vector3i pos, byte value) { */ void regenerate(Vector3ic pos, byte value); - @Deprecated - default void regenerate(Vector3i pos, byte value) { - regenerate(JomlUtil.from(pos), value); + /** + * Populates a target array with the minimum value adjacent to each location, including the location itself. + * + * @param source + * @param target + * @param populateMargins Whether to populate the edges of the target array + */ + static void populateMinAdjacent2D(int[] source, int[] target, int dimX, int dimY, boolean populateMargins) { + System.arraycopy(source, 0, target, 0, target.length); + + // 0 < x < dimX - 1; 0 < y < dimY - 1 + for (int y = 1; y < dimY - 1; ++y) { + for (int x = 1; x < dimX - 1; ++x) { + target[x + y * dimX] = Math.min(Math.min(source[x + (y - 1) * dimX], source[x + (y + 1) * dimX]), + Math.min(source[x + 1 + y * dimX], source[x - 1 + y * dimX])); + } + } + + if (populateMargins) { + // x == 0, y == 0 + target[0] = Math.min(source[1], source[dimX]); + + // 0 < x < dimX - 1, y == 0 + for (int x = 1; x < dimX - 1; ++x) { + target[x] = Math.min(source[x - 1], Math.min(source[x + 1], source[x + dimX])); + } + + // x == dimX - 1, y == 0 + target[dimX - 1] = Math.min(source[2 * dimX - 1], source[dimX - 2]); + + // 0 < y < dimY - 1 + for (int y = 1; y < dimY - 1; ++y) { + // x == 0 + target[y * dimX] = Math.min(source[dimX * (y - 1)], Math.min(source[dimX * (y + 1)], source[1 + dimX * y])); + // x == dimX - 1 + target[dimX - 1 + y * dimX] = Math.min(source[dimX - 1 + dimX * (y - 1)], Math.min(source[dimX - 1 + dimX * (y + 1)], source[dimX - 2 + dimX * y])); + } + // x == 0, y == dimY - 1 + target[dimX * (dimY - 1)] = Math.min(source[1 + dimX * (dimY - 1)], source[dimX * (dimY - 2)]); + + // 0 < x < dimX - 1; y == dimY - 1 + for (int x = 1; x < dimX - 1; ++x) { + target[x + dimX * (dimY - 1)] = Math.min(source[x - 1 + dimX * (dimY - 1)], Math.min(source[x + 1 + dimX * (dimY - 1)], source[x + dimX * (dimY - 2)])); + } + + // x == dimX - 1; y == dimY - 1 + target[dimX - 1 + dimX * (dimY - 1)] = Math.min(source[dimX - 2 + dimX * (dimY - 1)], source[dimX - 1 + dimX * (dimY - 2)]); + } } } diff --git a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java index ce1e65da538..811d3d4f4d9 100644 --- a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java @@ -310,7 +310,7 @@ private void propagateDepth(LitChunk adjChunk, Side side, boolean propagateExter int[] adjDepth = new int[depths.length]; int dimA = (side == Side.LEFT || side == Side.RIGHT) ? Chunks.SIZE_Y : Chunks.SIZE_X; int dimB = (side == Side.FRONT || side == Side.BACK) ? Chunks.SIZE_Y : Chunks.SIZE_Z; - ChunkMath.populateMinAdjacent2D(depths, adjDepth, dimA, dimB, !propagateExternal); + BatchPropagator.populateMinAdjacent2D(depths, adjDepth, dimA, dimB, !propagateExternal); if (propagateExternal) { for (int y = 0; y < dimB; ++y) { diff --git a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java index 7bc009ea7af..db4d450a67a 100644 --- a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java @@ -5,7 +5,6 @@ import com.google.common.collect.Sets; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.world.block.Block; @@ -184,7 +183,7 @@ public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boole propagateSweep(chunk, adjChunk, depth, startingRegen); int[] adjDepths = new int[depth.length]; - ChunkMath.populateMinAdjacent2D(depth, adjDepths, Chunks.SIZE_X, Chunks.SIZE_Z, !propagateExternal); + BatchPropagator.populateMinAdjacent2D(depth, adjDepths, Chunks.SIZE_X, Chunks.SIZE_Z, !propagateExternal); if (propagateExternal) { for (int z = 0; z < Chunks.SIZE_Z; ++z) { adjDepths[z * Chunks.SIZE_X] = 0; @@ -197,7 +196,7 @@ public void propagateBetween(LitChunk chunk, LitChunk adjChunk, Side side, boole } int[] adjStartingRegen = new int[depth.length]; - ChunkMath.populateMinAdjacent2D(startingRegen, adjStartingRegen, Chunks.SIZE_X, Chunks.SIZE_Z, true); + BatchPropagator.populateMinAdjacent2D(startingRegen, adjStartingRegen, Chunks.SIZE_X, Chunks.SIZE_Z, true); markForPropagation(adjChunk, depth, startingRegen, adjDepths, adjStartingRegen); } @@ -210,31 +209,19 @@ private void markForPropagation(LitChunk toChunk, int[] depth, int[] startingReg int depthIndex = x + Chunks.SIZE_X * z; int start = startingRegen[depthIndex]; int adjStart = adjStartingRegen[depthIndex]; + int initialDepth; if (start - adjStart > 1) { - int initialDepth = Math.max(Chunks.SUNLIGHT_REGEN_THRESHOLD - start, 0); - int finalDepth = depth[depthIndex]; - - int strength = Math.min(start + initialDepth - Chunks.SUNLIGHT_REGEN_THRESHOLD + 1, Chunks.MAX_SUNLIGHT); - - for (int i = initialDepth; i <= finalDepth; ++i) { - sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, Chunks.SIZE_Y - i - 1, z), - (byte) (strength)); - if (strength < Chunks.MAX_SUNLIGHT) { - strength++; - } - } + initialDepth = Math.max(Chunks.SUNLIGHT_REGEN_THRESHOLD - start, 0); } else { - int initialDepth = Math.max(adjDepths[depthIndex], Chunks.SUNLIGHT_REGEN_THRESHOLD - start); - byte strength = (byte) Math.min(Chunks.MAX_SUNLIGHT, start + initialDepth - Chunks.SUNLIGHT_REGEN_THRESHOLD + 1); - for (int i = initialDepth; i <= depth[depthIndex]; ++i) { - sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, Chunks.SIZE_Y - i - 1, z), strength); - if (strength < Chunks.MAX_SUNLIGHT) { - strength++; - } - pos.y--; + initialDepth = Math.max(Chunks.SUNLIGHT_REGEN_THRESHOLD - start, adjDepths[depthIndex]); + } + byte strength = (byte) Math.min(Chunks.MAX_SUNLIGHT, start + initialDepth - Chunks.SUNLIGHT_REGEN_THRESHOLD + 1); + for (int i = initialDepth; i <= depth[depthIndex]; ++i) { + sunlightPropagator.propagateFrom(toChunk.chunkToWorldPosition(x, Chunks.SIZE_Y - i - 1, z, pos), strength); + if (strength < Chunks.MAX_SUNLIGHT) { + strength++; } } - } } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java index 758fbbb07fa..f68a57a3617 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java @@ -16,8 +16,8 @@ package org.terasology.world.propagation.light; +import org.joml.Vector3i; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.LitChunk; @@ -51,13 +51,14 @@ public static void generateInternalLighting(LitChunk chunk) { */ private static void populateLight(LitChunk chunk) { BatchPropagator lightPropagator = new StandardBatchPropagator(LIGHT_RULES, new SingleChunkView(LIGHT_RULES, chunk)); + Vector3i pos = new Vector3i(); for (int x = 0; x < Chunks.SIZE_X; x++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { for (int y = 0; y < Chunks.SIZE_Y; y++) { Block block = chunk.getBlock(x, y, z); if (block.getLuminance() > 0) { chunk.setLight(x, y, z, block.getLuminance()); - lightPropagator.propagateFrom(new Vector3i(x, y, z), block.getLuminance()); + lightPropagator.propagateFrom(pos.set(x,y,z), block.getLuminance()); } } } @@ -74,11 +75,12 @@ private static void populateSunlight(LitChunk chunk) { PropagationRules sunlightRules = new SunlightPropagationRules(chunk); BatchPropagator lightPropagator = new StandardBatchPropagator(sunlightRules, new SingleChunkView(sunlightRules, chunk)); + Vector3i pos = new Vector3i(); for (int x = 0; x < Chunks.SIZE_X; x++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { /* Start at the bottom of the chunk and then move up until the max sunlight level */ for (int y = 0; y < Chunks.MAX_SUNLIGHT; y++) { - Vector3i pos = new Vector3i(x, y, z); + pos.set(x, y, z); Block block = chunk.getBlock(x, y, z); byte light = sunlightRules.getFixedValue(block, pos); if (light > 0) { From 8a4630505df5dfcdac4c380a148c22ea62783ad4 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 13 Jan 2021 13:56:33 -0800 Subject: [PATCH 116/259] feat(JOML): migrate TelemetrySystem (#4397) --- .../java/org/terasology/telemetry/TelemetrySystem.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/src/main/java/org/terasology/telemetry/TelemetrySystem.java b/engine/src/main/java/org/terasology/telemetry/TelemetrySystem.java index e9b7a0bf427..69beeb3fb36 100644 --- a/engine/src/main/java/org/terasology/telemetry/TelemetrySystem.java +++ b/engine/src/main/java/org/terasology/telemetry/TelemetrySystem.java @@ -16,6 +16,7 @@ package org.terasology.telemetry; import com.snowplowanalytics.snowplow.tracker.emitter.Emitter; +import org.joml.Vector3f; import org.terasology.config.Config; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -23,7 +24,6 @@ import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.UpdateSubscriberSystem; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.geom.Vector3f; import org.terasology.registry.In; import org.terasology.telemetry.metrics.BlockDestroyedMetric; import org.terasology.telemetry.metrics.BlockPlacedMetric; @@ -78,7 +78,7 @@ public void update(float delta) { // the first frame when the local player is valid if (previousPos == null) { setGamePlayStatsComponent(); - previousPos = localPlayer.getPosition(); + previousPos = localPlayer.getPosition(new Vector3f()); } else { recordDistanceTraveled(); recordPlayTime(); @@ -132,10 +132,10 @@ private void setGamePlayStatsComponent() { } private void recordDistanceTraveled() { - Vector3f position = localPlayer.getPosition(); + Vector3f position = localPlayer.getPosition(new Vector3f()); float distanceMoved = position.distance(previousPos); gamePlayStatsComponent.distanceTraveled += distanceMoved; - previousPos = position; + previousPos.set(position); localPlayer.getCharacterEntity().addOrSaveComponent(gamePlayStatsComponent); } From 19fde4cd87c107f80b76b4f5ec68cd2ffb17457e Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 16 Jan 2021 23:21:26 +0100 Subject: [PATCH 117/259] feat(joml): migrate BlockAppearance (#4404) --- .../rendering/assets/texture/BasicTextureRegion.java | 6 +++--- .../org/terasology/world/block/BlockAppearance.java | 11 +++++------ .../world/block/internal/BlockBuilder.java | 12 +++++++----- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java b/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java index 8b3ae45ec14..58dc66be382 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java @@ -17,11 +17,11 @@ import org.joml.Rectanglef; import org.joml.Rectanglei; +import org.joml.Vector2fc; import org.joml.Vector2i; import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import org.terasology.math.geom.Rect2f; -import org.terasology.math.geom.Vector2f; /** */ @@ -34,8 +34,8 @@ public BasicTextureRegion(Texture texture, Rect2f region) { this.region = JomlUtil.from(region); } - public BasicTextureRegion(Texture texture, Vector2f offset, Vector2f size) { - this(texture, Rect2f.createFromMinAndSize(offset, size)); + public BasicTextureRegion(Texture texture, Vector2fc offset, Vector2fc size) { + this(texture, Rect2f.createFromMinAndSize(JomlUtil.from(offset), JomlUtil.from(size))); } @Override diff --git a/engine/src/main/java/org/terasology/world/block/BlockAppearance.java b/engine/src/main/java/org/terasology/world/block/BlockAppearance.java index d7d7949420f..827344e7eaa 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockAppearance.java +++ b/engine/src/main/java/org/terasology/world/block/BlockAppearance.java @@ -17,8 +17,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Maps; - -import org.terasology.math.geom.Vector2f; +import org.joml.Vector2f; +import org.joml.Vector2fc; import org.terasology.world.block.shapes.BlockMeshPart; import java.util.EnumMap; @@ -31,7 +31,7 @@ public class BlockAppearance { private Map blockParts; - private Map textureAtlasPos = new EnumMap<>(BlockPart.class); + private Map textureAtlasPos = new EnumMap<>(BlockPart.class); public BlockAppearance() { blockParts = Maps.newEnumMap(BlockPart.class); @@ -41,7 +41,7 @@ public BlockAppearance() { } } - public BlockAppearance(Map blockParts, Map textureAtlasPos) { + public BlockAppearance(Map blockParts, Map textureAtlasPos) { Preconditions.checkNotNull(blockParts); Preconditions.checkNotNull(textureAtlasPos); this.blockParts = blockParts; @@ -55,8 +55,7 @@ public BlockMeshPart getPart(BlockPart part) { return blockParts.get(part); } - public Vector2f getTextureAtlasPos(BlockPart part) { + public Vector2fc getTextureAtlasPos(BlockPart part) { return new Vector2f(textureAtlasPos.get(part)); } - } diff --git a/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java b/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java index b44e3222017..470d679703e 100644 --- a/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java +++ b/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java @@ -17,11 +17,12 @@ import com.google.common.base.Strings; import com.google.common.collect.Maps; +import org.joml.Quaternionf; +import org.joml.Vector2f; import org.terasology.math.JomlUtil; -import org.terasology.utilities.Assets; import org.terasology.math.Rotation; import org.terasology.math.Side; -import org.terasology.math.geom.Vector2f; +import org.terasology.utilities.Assets; import org.terasology.world.block.Block; import org.terasology.world.block.BlockAppearance; import org.terasology.world.block.BlockBuilderHelper; @@ -188,15 +189,16 @@ private BlockAppearance createAppearance(BlockShape shape, Map Date: Sat, 16 Jan 2021 20:52:21 -0800 Subject: [PATCH 118/259] doc(build): createVersionTask --- facades/PC/build.gradle.kts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 147645d7125..da5d4ae2c81 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -209,8 +209,16 @@ tasks.register("server") { * See also publish.gradle, included near the top. */ -// Preps a version file to bundle with PC dists. This eventually goes into the root of a zip file +/** + * Create a human-readable file with version and build information. + * + * This goes in to the root of the distribution where it can easily be found and read by humans. + * For build details in a easily parsed format, see the `versionInfo.properties` resource added + * in engine's build. + */ val createVersionFile = tasks.register("createVersionFile") { + this.description = "Create a human-readable file with version and build information." + inputs.property("dateTime", startDateTimeString) onlyIf { env["BUILD_URL"] != null } from(templatesDir) From a7e661ba217ccd99fe1aaa051f6e57c64e237362 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:53:37 -0800 Subject: [PATCH 119/259] refactor (build): move jar task to distribution-related section --- facades/PC/build.gradle.kts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index da5d4ae2c81..32deddcc869 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -93,17 +93,6 @@ dependencies { runtimeOnly(platform(project(":modules"))) } -// Instructions for packaging a jar file for the PC facade -tasks.named("jar") { - manifest { - //TODO: Maybe later add the engine's version number into here? - attributes["Main-Class"] = mainClassName - attributes["Class-Path"] = configurations["runtimeClasspath"].map { it.name }.joinToString(" ") - attributes["Implementation-Title"] = "Terasology-" + project.name - attributes["Implementation-Version"] = """${env["BUILD_NUMBER"]}, ${env["GIT_BRANCH"]}, ${env["BUILD_ID"]}""" - } -} - configurations { register("modules") { description = "for fetching modules for running a server" @@ -209,6 +198,16 @@ tasks.register("server") { * See also publish.gradle, included near the top. */ +tasks.named("jar") { + manifest { + //TODO: Maybe later add the engine's version number into here? + attributes["Main-Class"] = mainClassName + attributes["Class-Path"] = configurations["runtimeClasspath"].map { it.name }.joinToString(" ") + attributes["Implementation-Title"] = "Terasology-" + project.name + attributes["Implementation-Version"] = """${env["BUILD_NUMBER"]}, ${env["GIT_BRANCH"]}, ${env["BUILD_ID"]}""" + } +} + /** * Create a human-readable file with version and build information. * From d4ed1827d9e560752626e08a061ec9f0b5ba6f29 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:55:26 -0800 Subject: [PATCH 120/259] chore(build): allow createVersionFile to run regardless of environment --- facades/PC/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 32deddcc869..5cdba6776e5 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -219,7 +219,6 @@ val createVersionFile = tasks.register("createVersionFile") { this.description = "Create a human-readable file with version and build information." inputs.property("dateTime", startDateTimeString) - onlyIf { env["BUILD_URL"] != null } from(templatesDir) into("$buildDir/versionfile") include(versionFileName) From b8b058055a3976a2e2bbf0c5afe051ab0b14a66c Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 16 Jan 2021 21:25:01 -0800 Subject: [PATCH 121/259] chore (build): name facade's jar Terasology.jar Launcher invokes it by naming this file, not by class lookup. --- facades/PC/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 5cdba6776e5..2bbcae0a714 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -199,6 +199,9 @@ tasks.register("server") { */ tasks.named("jar") { + // Launcher expects the main class to be in the file with this name. + archiveFileName.set("Terasology.jar") + manifest { //TODO: Maybe later add the engine's version number into here? attributes["Main-Class"] = mainClassName From 2aed3659e562749092452f72c0b6216ad603fd22 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 17 Jan 2021 01:31:57 -0800 Subject: [PATCH 122/259] feat(JOML): migrate BlockLifecycleEvent (#4405) * feat(JOML): migrate BlockLifecycleEvent * fix: throw `NoSuchElementException` instead of NPE * add FIXME comment about mismatch of blockCount and iterator Co-authored-by: Tobias Nett --- .../world/block/BlockLifecycleEvent.java | 67 +++++++++++++++++-- .../block/internal/BlockPositionIterator.java | 67 ------------------- 2 files changed, 61 insertions(+), 73 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/world/block/internal/BlockPositionIterator.java diff --git a/engine/src/main/java/org/terasology/world/block/BlockLifecycleEvent.java b/engine/src/main/java/org/terasology/world/block/BlockLifecycleEvent.java index b88a06c39ca..1a5a61d3799 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockLifecycleEvent.java +++ b/engine/src/main/java/org/terasology/world/block/BlockLifecycleEvent.java @@ -16,14 +16,32 @@ package org.terasology.world.block; import gnu.trove.list.TIntList; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; import org.terasology.world.BlockEntityRegistry; -import org.terasology.world.block.internal.BlockPositionIterator; + +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; /** */ -public abstract class BlockLifecycleEvent implements Event { +//FIXME: There is a mismatch between `blockCount` and iterated blocks. +// I don't get what this event is about, and how it should behave. The `TIntList positions` is a flattened list +// of positions. So if this event affects +// [(0,0,0), (1,2,3), (4,5,6)] +// then `positions` would be: +// [0,0,0, 1,2,3, 4,5,6] +// But whether a block listed in positions is actually returned depends on whether there's a permanent block +// entity registered or not? Doesn't this lead to a mismatch between the size as returned by blockCount and +// the actual amount of positions returned by the iterator? So, it could be that +// event.blockCount() == n +// but +// for (Vector3ic pos: event) { ... } +// only iterates over m < n blocks? Maybe we should not inline the iterator here, but rather make it explicit +// that it will only iterator over `blockPositionsWithNonPermanentEntities`. +public abstract class BlockLifecycleEvent implements Event, Iterable { private TIntList positions; private BlockEntityRegistry registry; @@ -32,11 +50,48 @@ public BlockLifecycleEvent(TIntList positions, BlockEntityRegistry registry) { this.positions = positions; } - public Iterable getBlockPositions() { - return () -> new BlockPositionIterator(positions, registry); + @Override + public Iterator iterator() { + if (positions.size() < 3) { + return Collections.emptyIterator(); + } + return new Iterator() { + private Vector3i next = new Vector3i( + positions.get(0), + positions.get(1), + positions.get(2)); + private final Vector3i current = new Vector3i(); + private int index = 3; + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public Vector3ic next() { + if (next == null) { + throw new NoSuchElementException(); + } + current.set(next); + fetchNext(); + return current; + } + + private void fetchNext() { + while (index < positions.size() - 2) { + next.x = positions.get(index++); + next.y = positions.get(index++); + next.z = positions.get(index++); + if (!registry.hasPermanentBlockEntity(next)) { + return; + } + } + next = null; + } + }; } public int blockCount() { - return positions.size(); + return positions.size() / 3; } } diff --git a/engine/src/main/java/org/terasology/world/block/internal/BlockPositionIterator.java b/engine/src/main/java/org/terasology/world/block/internal/BlockPositionIterator.java deleted file mode 100644 index 96b68f6eeea..00000000000 --- a/engine/src/main/java/org/terasology/world/block/internal/BlockPositionIterator.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.world.block.internal; - -import gnu.trove.list.TIntList; -import org.terasology.math.geom.Vector3i; -import org.terasology.world.BlockEntityRegistry; - -import java.util.Iterator; - -/** - */ -public class BlockPositionIterator implements Iterator { - private BlockEntityRegistry registry; - private TIntList positionList; - private int i; - private Vector3i nextResult = new Vector3i(); - - public BlockPositionIterator(TIntList positionList, BlockEntityRegistry registry) { - this.positionList = positionList; - this.registry = registry; - iterate(); - } - - @Override - public boolean hasNext() { - return nextResult != null; - } - - @Override - public Vector3i next() { - Vector3i result = new Vector3i(nextResult); - iterate(); - - return result; - } - - private void iterate() { - while (i < positionList.size() - 2) { - nextResult.x = positionList.get(i++); - nextResult.y = positionList.get(i++); - nextResult.z = positionList.get(i++); - if (!registry.hasPermanentBlockEntity(nextResult)) { - return; - } - } - nextResult = null; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("Remove not supported on BlockPositionIterator"); - } -} From c4c866da27e375f1faebbc8dfd6446db498272af Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 10:46:43 -0800 Subject: [PATCH 123/259] refactor (build): move configurations to before dependencies where they're used --- facades/PC/build.gradle.kts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 2bbcae0a714..017d67d188a 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -79,6 +79,13 @@ logger.info("PC VERSION: {}", version) // Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor group = "org.terasology.facades" +configurations { + register("modules") { + description = "for fetching modules for running a server" + isTransitive = false + } +} + dependencies { implementation(project(":engine")) implementation(group = "org.reflections", name = "reflections", version = "0.9.10") @@ -93,13 +100,6 @@ dependencies { runtimeOnly(platform(project(":modules"))) } -configurations { - register("modules") { - description = "for fetching modules for running a server" - isTransitive = false - } -} - /**************************************** * Run Targets */ From 2b8a149cefceaaf99bc0ef273ea1341fa44064e8 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 11:12:17 -0800 Subject: [PATCH 124/259] chore (build): include native libs in distribution --- facades/PC/build.gradle.kts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 017d67d188a..2daf7aa4e42 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -84,6 +84,9 @@ configurations { description = "for fetching modules for running a server" isTransitive = false } + register("natives") { + description = "native libraries (.dll and .so)" + } } dependencies { @@ -94,6 +97,8 @@ dependencies { // TODO: Consider whether we can move the CR dependency back here from the engine, where it is referenced from the main menu implementation(group = "org.terasology.crashreporter", name = "cr-terasology", version = "4.1.0") + "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) + // Make sure any local module builds are up-to-date and have their dependencies by declaring // a runtime dependency on whatever the `:modules` subproject declares. // This won't add anything if there are no modules checked out. @@ -305,6 +310,9 @@ distributions { filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) } from(createVersionFile) + from(configurations.named("natives")) { + into(dirNatives) + } } } } From ffaacc735e3ad1ea1801ffc76f4e7347a3bf7fee Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 11:15:29 -0800 Subject: [PATCH 125/259] chore (build): replace dist tasks Configure things so we can take advantage of more of gradle's defaults. --- facades/PC/build.gradle.kts | 63 +++++-------------------------------- 1 file changed, 8 insertions(+), 55 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 2daf7aa4e42..9ffbcb80823 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -240,67 +240,20 @@ val createVersionFile = tasks.register("createVersionFile") { filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) } -// Main application dist target. Does NOT include any modules. -tasks.register("distApp") { - description = "Creates an application package for distribution" +tasks.register("distForLauncher") { group = "terasology dist" + description = "Bundles the project to a Launcher-compatible layout." - dependsOn("createVersionFile") - dependsOn(":extractNatives") - dependsOn("jar") - - into("${distsDirectory.get().asFile}/app") - from ("$rootDir/README.markdown") { - filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) - rename("README.markdown", "README") - } - from ("$rootDir/LICENSE") { - filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) - } - from ("$rootDir/NOTICE") { - filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) - } - from("launchScripts") { - exclude("TeraEd.exe") - } - - from("$buildDir/$versionFileName") {} - - into(subDirLibs) { - from(configurations.runtimeClasspath) - from(tasks.getByPath(":engine:jar")) - from("$buildDir/libs") { - include("*.jar") - rename { - "Terasology.jar" - } - } - } - into(dirNatives) { - from("$rootDir/$dirNatives") - } -} - -tasks.register("distPCZip") { - group = "terasology dist" - dependsOn("distApp") - from("${distsDirectory.get().asFile}/app") archiveFileName.set("Terasology.zip") -} -tasks.register("distForLauncher") { - group = "terasology dist" - - into(rootDirDist) - from(tasks.getByName("distPCZip")) - - into("../resources/main/org/terasology/version") { - from("$rootDir/engine/build/classes/org/terasology/version") { - include("versionInfo.properties") - } - } + // Launcher expects `libs/Terasology.jar`, no containing folder + this.with(distributions.getByName("main").contents) } +// NOTE: If you build a distribution while you have modules, all the test dependencies are in here. +// They're "optional" in module.txt and gradle doesn't know how to tell which are runtime and which are +// test-only. + distributions { main { contents { From 6f5af62a42025991aab0df9a4b1a70b7d1ec0ff3 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 11:19:05 -0800 Subject: [PATCH 126/259] chore (build): remove old facade launch scripts The exe versions were unmaintained and gradle provides startup scripts that are much better about compatibility than we were. --- facades/PC/launchScripts/TeraEd.exe | Bin 26112 -> 0 bytes facades/PC/launchScripts/Terasology.x64.exe | Bin 282624 -> 0 bytes facades/PC/launchScripts/Terasology.x86.exe | Bin 244224 -> 0 bytes facades/PC/launchScripts/run_linux.sh | 5 --- facades/PC/launchScripts/run_macosx.command | 6 ---- .../PC/launchScriptsSrc/LauncherTeraEd.xml | 30 ------------------ facades/PC/launchScriptsSrc/README.MD | 4 --- 7 files changed, 45 deletions(-) delete mode 100644 facades/PC/launchScripts/TeraEd.exe delete mode 100644 facades/PC/launchScripts/Terasology.x64.exe delete mode 100644 facades/PC/launchScripts/Terasology.x86.exe delete mode 100755 facades/PC/launchScripts/run_linux.sh delete mode 100755 facades/PC/launchScripts/run_macosx.command delete mode 100644 facades/PC/launchScriptsSrc/LauncherTeraEd.xml delete mode 100644 facades/PC/launchScriptsSrc/README.MD diff --git a/facades/PC/launchScripts/TeraEd.exe b/facades/PC/launchScripts/TeraEd.exe deleted file mode 100644 index 266c5e9fd1f890a73858bf6eabe0a8b987b97ced..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26112 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 XW>8Ly$c%ot_D7JD{q^%-!h!z@A;G(# diff --git a/facades/PC/launchScripts/Terasology.x64.exe b/facades/PC/launchScripts/Terasology.x64.exe deleted file mode 100644 index 5bdffcca1e8f91b354afe8e15ac552f4ad887122..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282624 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
_LwU9{v$9tR5BGm3SF|IWx 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 diff --git a/facades/PC/launchScripts/Terasology.x86.exe b/facades/PC/launchScripts/Terasology.x86.exe deleted file mode 100644 index 0026bbb41762a07e3a4b0f03934fc514ef082c96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244224 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 - - true - gui - .\libs\Terasology.jar - ..\launchScripts\TeraEd.exe - - - - normal - http://java.com/download - - false - - - - org.terasology.editor.TeraEd - Terasology.jar - - - - false - 1.8.0 - - preferJre - 64/32 - 128 - 1536 - - \ No newline at end of file diff --git a/facades/PC/launchScriptsSrc/README.MD b/facades/PC/launchScriptsSrc/README.MD deleted file mode 100644 index fb77673cd46..00000000000 --- a/facades/PC/launchScriptsSrc/README.MD +++ /dev/null @@ -1,4 +0,0 @@ - -For the sources of the normal Windows launcher, see the following repository: - -https://github.com/MovingBlocks/TerasologyJavaLauncher From 69e9b812df5ed896416f4e41855c9145eef32634 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sun, 17 Jan 2021 20:20:53 +0100 Subject: [PATCH 127/259] feat(JOML): migrate WorldProvider (#4408) * chore: remove unused imports * feat(JOML): migrate WorldProvider --- .../java/org/terasology/MapWorldProvider.java | 33 ++--- .../testUtil/WorldProviderCoreStub.java | 39 ++---- .../org/terasology/world/WorldProvider.java | 117 +++++++++++++----- .../generation/facets/ElevationFacet.java | 2 - .../generation/facets/SurfaceDepthFacet.java | 1 - .../facets/base/BaseBooleanFieldFacet2D.java | 1 - .../generation/facets/base/BaseFacet2D.java | 3 - .../facets/base/SparseObjectFacet3D.java | 1 - .../AbstractWorldProviderDecorator.java | 15 +-- .../internal/EntityAwareWorldProvider.java | 5 - .../world/internal/WorldProviderCore.java | 24 +++- .../world/internal/WorldProviderCoreImpl.java | 92 ++++++-------- .../world/internal/WorldProviderWrapper.java | 71 +++-------- 13 files changed, 184 insertions(+), 220 deletions(-) diff --git a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java index a22e1567ef0..639fc4ed5e2 100644 --- a/engine-tests/src/main/java/org/terasology/MapWorldProvider.java +++ b/engine-tests/src/main/java/org/terasology/MapWorldProvider.java @@ -16,18 +16,17 @@ package org.terasology; import com.google.common.collect.Maps; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; import org.terasology.world.chunks.Chunk; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; import org.terasology.world.generation.impl.EntityBufferImpl; @@ -47,8 +46,8 @@ */ public class MapWorldProvider implements WorldProviderCore { - private Map blocks = Maps.newHashMap(); - private Map chunks = Maps.newHashMap(); + private Map blocks = Maps.newHashMap(); + private Map chunks = Maps.newHashMap(); private WorldGenerator worldGenerator; private BlockManager blockManager; private ExtraBlockDataManager extraDataManager; @@ -83,27 +82,16 @@ public boolean isBlockRelevant(int x, int y, int z) { return false; } - @Override - public boolean isRegionRelevant(Region3i region) { - return false; - } - @Override public boolean isRegionRelevant(BlockRegionc region) { return false; } - @Override - public Block setBlock(Vector3i pos, Block type) { - return blocks.put(pos, type); - } - @Override public Block setBlock(Vector3ic pos, Block type) { - return blocks.put(JomlUtil.from(pos), type); + return blocks.put(new Vector3i(pos), type); } - @Override public Block getBlock(int x, int y, int z) { Vector3i pos = new Vector3i(x, y, z); @@ -113,15 +101,15 @@ public Block getBlock(int x, int y, int z) { } // TODO block manager - Vector3i chunkPos = ChunkMath.calcChunkPos(pos); + Vector3i chunkPos = Chunks.toChunkPos(pos, new Vector3i()); Chunk chunk = chunks.get(chunkPos); if (chunk == null && worldGenerator != null) { - chunk = new ChunkImpl(chunkPos, blockManager, extraDataManager); + chunk = new ChunkImpl(JomlUtil.from(chunkPos), blockManager, extraDataManager); worldGenerator.createChunk(chunk, entityBuffer); chunks.put(chunkPos, chunk); } if (chunk != null) { - return chunk.getBlock(ChunkMath.calcRelativeBlockPos(pos.x, pos.y, pos.z)); + return chunk.getBlock(Chunks.toRelative(pos, pos)); } return null; } @@ -139,7 +127,6 @@ public String getSeed() { @Override public WorldInfo getWorldInfo() { return null; - } @Override @@ -148,7 +135,7 @@ public ChunkViewCore getLocalView(Vector3ic chunkPos) { } @Override - public ChunkViewCore getWorldViewAround(Vector3i chunk) { + public ChunkViewCore getWorldViewAround(Vector3ic chunk) { return null; } @@ -168,7 +155,7 @@ public byte getTotalLight(int x, int y, int z) { } @Override - public int setExtraData(int index, Vector3i pos, int value) { + public int setExtraData(int index, Vector3ic pos, int value) { return 0; } diff --git a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java index 8a11a8e6573..4ae292f160e 100644 --- a/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java +++ b/engine-tests/src/main/java/org/terasology/testUtil/WorldProviderCoreStub.java @@ -17,11 +17,9 @@ package org.terasology.testUtil; import com.google.common.collect.Maps; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; @@ -35,15 +33,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.Map; /** */ public class WorldProviderCoreStub implements WorldProviderCore { - private Map blocks = Maps.newHashMap(); - private ArrayList> extraData = new ArrayList<>(); + private Map blocks = Maps.newHashMap(); + private ArrayList> extraData = new ArrayList<>(); private Block air; public WorldProviderCoreStub(Block air) { @@ -90,7 +87,7 @@ public ChunkViewCore getLocalView(Vector3ic chunkPos) { } @Override - public ChunkViewCore getWorldViewAround(Vector3i chunk) { + public ChunkViewCore getWorldViewAround(Vector3ic chunk) { return null; //To change body of implemented methods use File | Settings | File Templates. } @@ -99,40 +96,20 @@ public boolean isBlockRelevant(int x, int y, int z) { return true; //To change body of implemented methods use File | Settings | File Templates. } - @Override - public boolean isRegionRelevant(Region3i region) { - return true; - } - @Override public boolean isRegionRelevant(BlockRegionc region) { return false; } - @Override - public Block setBlock(Vector3i pos, Block type) { - return this.setBlock(JomlUtil.from(pos), type); - } - @Override public Block setBlock(Vector3ic pos, Block type) { - Block old = blocks.put(JomlUtil.from(pos), type); + Block old = blocks.put(new Vector3i(pos), type); if (old == null) { return air; } return old; } - @Override - public Map setBlocks(Map blocksToPlace) { - Map result = new HashMap<>(blocks.size()); - for (Map.Entry entry : blocksToPlace.entrySet()) { - Block b = setBlock(entry.getKey(), entry.getValue()); - result.put(entry.getKey(), b); - } - return result; - } - @Override public Block getBlock(int x, int y, int z) { Block result = blocks.get(new Vector3i(x, y, z)); @@ -158,8 +135,8 @@ public byte getTotalLight(int x, int y, int z) { } @Override - public int setExtraData(int index, Vector3i pos, int value) { - Integer prevValue = getExtraDataLayer(index).put(pos, value); + public int setExtraData(int index, Vector3ic pos, int value) { + Integer prevValue = getExtraDataLayer(index).put(new Vector3i(pos), value); return prevValue == null ? 0 : prevValue; } @@ -168,7 +145,7 @@ public int getExtraData(int index, int x, int y, int z) { return getExtraDataLayer(index).getOrDefault(new Vector3i(x, y, z), 0); } - private Map getExtraDataLayer(int index) { + private Map getExtraDataLayer(int index) { while (extraData.size() <= index) { extraData.add(Maps.newHashMap()); } diff --git a/engine/src/main/java/org/terasology/world/WorldProvider.java b/engine/src/main/java/org/terasology/world/WorldProvider.java index 753f1caf51c..c4107ded7b1 100644 --- a/engine/src/main/java/org/terasology/world/WorldProvider.java +++ b/engine/src/main/java/org/terasology/world/WorldProvider.java @@ -17,6 +17,7 @@ import org.joml.Vector3fc; import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; @@ -37,7 +38,9 @@ public interface WorldProvider extends WorldProviderCore { * method will be replaced with JOML implementation {@link #isBlockRelevant(Vector3ic)}. */ @Deprecated - boolean isBlockRelevant(Vector3i pos); + default boolean isBlockRelevant(Vector3i pos) { + return isBlockRelevant(JomlUtil.from(pos)); + }; /** * An active block is in a chunk that is available and fully generated. @@ -55,7 +58,9 @@ public interface WorldProvider extends WorldProviderCore { * method will be replaced with JOML implementation {@link #isBlockRelevant(Vector3fc)}. */ @Deprecated - boolean isBlockRelevant(Vector3f pos); + default boolean isBlockRelevant(Vector3f pos) { + return isBlockRelevant(JomlUtil.from(pos)); + } /** * An active block is in a chunk that is available and fully generated. @@ -74,7 +79,9 @@ public interface WorldProvider extends WorldProviderCore { * method will be replaced with JOML implementation {@link #getBlock(Vector3fc)}. */ @Deprecated - Block getBlock(Vector3f pos); + default Block getBlock(Vector3f pos) { + return getBlock(JomlUtil.from(pos)); + } /** * Returns the block value at the given position. @@ -93,7 +100,9 @@ public interface WorldProvider extends WorldProviderCore { * method will be replaced with JOML implementation {@link #getBlock(Vector3ic)}. */ @Deprecated - Block getBlock(Vector3i pos); + default Block getBlock(Vector3i pos) { + return getBlock(JomlUtil.from(pos)); + } /** * Returns the block value at the given position. @@ -101,7 +110,9 @@ public interface WorldProvider extends WorldProviderCore { * @param pos The position * @return The block value at the given position */ - Block getBlock(Vector3ic pos); + default Block getBlock(Vector3ic pos) { + return getBlock(pos.x(), pos.y(), pos.z()); + } /** * Returns the light value at the given position. @@ -109,25 +120,37 @@ public interface WorldProvider extends WorldProviderCore { * @param pos The position * @return The block value at the given position */ - byte getLight(Vector3f pos); + byte getLight(Vector3fc pos); + + @Deprecated + default byte getLight(Vector3f pos) { + return getLight(JomlUtil.from(pos)); + } /** - * Returns the sunlight value at the given position. + * Returns the light value at the given position. * * @param pos The position * @return The block value at the given position */ - byte getSunlight(Vector3f pos); + byte getLight(Vector3ic pos); - byte getTotalLight(Vector3f pos); + default byte getLight(Vector3i pos) { + return getLight(JomlUtil.from(pos)); + } /** - * Returns the light value at the given position. + * Returns the sunlight value at the given position. * * @param pos The position * @return The block value at the given position */ - byte getLight(Vector3i pos); + byte getSunlight(Vector3fc pos); + + @Deprecated + default byte getSunlight(Vector3f pos) { + return getSunlight(JomlUtil.from(pos)); + } /** * Returns the sunlight value at the given position. @@ -135,9 +158,26 @@ public interface WorldProvider extends WorldProviderCore { * @param pos The position * @return The block value at the given position */ - byte getSunlight(Vector3i pos); + byte getSunlight(Vector3ic pos); + + @Deprecated + default byte getSunlight(Vector3i pos) { + return getSunlight(JomlUtil.from(pos)); + } + + byte getTotalLight(Vector3fc pos); - byte getTotalLight(Vector3i pos); + @Deprecated + default byte getTotalLight(Vector3f pos) { + return getTotalLight(JomlUtil.from(pos)); + } + + byte getTotalLight(Vector3ic pos); + + @Deprecated + default byte getTotalLight(Vector3i pos) { + return getTotalLight(JomlUtil.from(pos)); + } /** * Gets one of the per-block custom data values at the given position. Returns 0 outside the view. @@ -146,20 +186,14 @@ public interface WorldProvider extends WorldProviderCore { * @param pos * @return The (index)th extra-data value at the given position */ - int getExtraData(int index, Vector3i pos); + default int getExtraData(int index, Vector3ic pos) { + return getExtraData(index, pos.x(), pos.y(), pos.z()); + } - /** - * Sets one of the per-block custom data values at the given position, if it is within the view. - * You must not use this method with world gen code, call 'setExtraData' on chunk instead. - * - * @param index The index of the extra data field - * @param x - * @param y - * @param z - * @param value - * @return The replaced value - */ - int setExtraData(int index, int x, int y, int z, int value); + @Deprecated + default int getExtraData(int index, Vector3i pos) { + return getExtraData(index, pos.x, pos.y, pos.z); + } /** * Gets one of the per-block custom data values at the given position. Returns 0 outside the view. @@ -172,6 +206,11 @@ public interface WorldProvider extends WorldProviderCore { */ int getExtraData(String fieldName, int x, int y, int z); + @Deprecated + default int getExtraData(String fieldName, Vector3i pos) { + return getExtraData(fieldName, pos.x, pos.y, pos.z); + } + /** * Gets one of the per-block custom data values at the given position. Returns 0 outside the view. * @@ -179,7 +218,22 @@ public interface WorldProvider extends WorldProviderCore { * @param pos * @return The named extra-data value at the given position */ - int getExtraData(String fieldName, Vector3i pos); + default int getExtraData(String fieldName, Vector3ic pos) { + return getExtraData(fieldName, pos.x(), pos.y(), pos.z()); + } + + /** + * Sets one of the per-block custom data values at the given position, if it is within the view. + * You must not use this method with world gen code, call 'setExtraData' on chunk instead. + * + * @param index The index of the extra data field + * @param x + * @param y + * @param z + * @param value + * @return The replaced value + */ + int setExtraData(int index, int x, int y, int z, int value); /** * Sets one of the per-block custom data values at the given position, if it is within the view. @@ -203,5 +257,12 @@ public interface WorldProvider extends WorldProviderCore { * @param value * @return The replaced value */ - int setExtraData(String fieldName, Vector3i pos, int value); + default int setExtraData(String fieldName, Vector3ic pos, int value) { + return setExtraData(fieldName, pos.x(), pos.y(), pos.z(), value); + } + + @Deprecated + default int setExtraData(String fieldName, Vector3i pos, int value) { + return setExtraData(fieldName, pos.x, pos.y, pos.z, value); + } } diff --git a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java index fae752b8077..5dda20dcc2f 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/ElevationFacet.java @@ -3,8 +3,6 @@ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; -import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java index 11f71c6d0d2..439ac5d77d7 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/SurfaceDepthFacet.java @@ -15,7 +15,6 @@ */ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseFieldFacet2D; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java index f57a2a86e9a..43cdaf7efb9 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseBooleanFieldFacet2D.java @@ -17,7 +17,6 @@ import com.google.common.base.Preconditions; import org.joml.Vector2ic; -import org.terasology.math.geom.Vector2i; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java index ade1f74c402..d89c5321b11 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/BaseFacet2D.java @@ -16,11 +16,8 @@ package org.terasology.world.generation.facets.base; import org.joml.Vector3i; -import org.terasology.math.geom.Rect2i; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockArea; import org.terasology.world.block.BlockAreac; -import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.WorldFacet2D; diff --git a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java index e174d714cdd..1800df0d6a1 100644 --- a/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java +++ b/engine/src/main/java/org/terasology/world/generation/facets/base/SparseObjectFacet3D.java @@ -19,7 +19,6 @@ import com.google.common.collect.Maps; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockRegionc; import org.terasology.world.generation.Border3D; diff --git a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java index 4f5dcd5a805..42a7bcf6d50 100644 --- a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java +++ b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java @@ -18,7 +18,6 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.Region3i; import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.block.Block; @@ -80,7 +79,7 @@ public ChunkViewCore getLocalView(Vector3ic chunkPos) { } @Override - public ChunkViewCore getWorldViewAround(Vector3i chunk) { + public ChunkViewCore getWorldViewAround(Vector3ic chunk) { return base.getWorldViewAround(chunk); } @@ -89,21 +88,11 @@ public boolean isBlockRelevant(int x, int y, int z) { return base.isBlockRelevant(x, y, z); } - @Override - public boolean isRegionRelevant(Region3i region) { - return base.isRegionRelevant(region); - } - @Override public boolean isRegionRelevant(BlockRegionc region) { return base.isRegionRelevant(region); } - @Override - public Block setBlock(Vector3i pos, Block type) { - return base.setBlock(pos, type); - } - @Override public Block setBlock(Vector3ic pos, Block type) { return base.setBlock(pos, type); @@ -140,7 +129,7 @@ public int getExtraData(int index, int x, int y, int z) { } @Override - public int setExtraData(int index, Vector3i pos, int value) { + public int setExtraData(int index, Vector3ic pos, int value) { return base.setExtraData(index, pos, value); } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index 4a607d02b6d..8b6197bf0c5 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -115,11 +115,6 @@ public void shutdown() { entityManager.unsubscribe(this); } - @Override - public Block setBlock(Vector3i pos, Block type) { - return this.setBlock(JomlUtil.from(pos), type); - } - @Override public Block setBlock(Vector3ic pos, Block type) { if (GameThread.isCurrentThread()) { diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java index 79a91089ccf..93b70281bfc 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java @@ -18,6 +18,7 @@ import com.google.common.collect.Maps; import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.math.JomlUtil; import org.terasology.math.Region3i; import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; @@ -82,8 +83,12 @@ public interface WorldProviderCore { * @param chunk * @return A world view of the chunks around the desired chunk, uncentered. */ - ChunkViewCore getWorldViewAround(Vector3i chunk); + ChunkViewCore getWorldViewAround(Vector3ic chunk); + @Deprecated + default ChunkViewCore getWorldViewAround(Vector3i chunk) { + return getWorldViewAround(JomlUtil.from(chunk)); + } /** * An active block is in a chunk that is available and fully generated. @@ -95,7 +100,10 @@ public interface WorldProviderCore { */ boolean isBlockRelevant(int x, int y, int z); - boolean isRegionRelevant(Region3i region); + @Deprecated + default boolean isRegionRelevant(Region3i region) { + return isRegionRelevant(JomlUtil.from(region)); + } boolean isRegionRelevant(BlockRegionc region); @@ -109,8 +117,9 @@ public interface WorldProviderCore { * method will be replaced with JOML implementation {@link #setBlock(Vector3ic, Block)}. */ @Deprecated - Block setBlock(Vector3i pos, Block type); - + default Block setBlock(Vector3i pos, Block type) { + return setBlock(JomlUtil.from(pos), type); + } /** * Places a block of a specific type at a given position @@ -191,7 +200,12 @@ default Map setBlocks(Map blocks) { * @param value * @return The replaced value */ - int setExtraData(int index, Vector3i pos, int value); + int setExtraData(int index, Vector3ic pos, int value); + + @Deprecated + default int setExtraData(int index, Vector3i pos, int value) { + return setExtraData(index, JomlUtil.from(pos), value); + } /** * Disposes this world provider. diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index ae5f3a56800..f7d160d0f20 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -8,6 +8,7 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.context.Context; import org.terasology.engine.SimpleUri; @@ -15,8 +16,6 @@ import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.WorldComponent; import org.terasology.world.block.Block; @@ -53,6 +52,7 @@ import java.util.Set; /** + * */ public class WorldProviderCoreImpl implements WorldProviderCore { @@ -67,7 +67,7 @@ public class WorldProviderCoreImpl implements WorldProviderCore { private final List listeners = Lists.newArrayList(); - private final Map blockChanges = Maps.newHashMap(); + private final Map blockChanges = Maps.newHashMap(); private List propagators = Lists.newArrayList(); private Block unloadedBlock; @@ -91,13 +91,15 @@ public WorldProviderCoreImpl(String title, String customTitle, String seed, long PropagationRules sunlightRules = new SunlightPropagationRules(regenWorldView); PropagatorWorldView sunlightWorldView = new SunlightWorldView(chunkProvider); BatchPropagator sunlightPropagator = new StandardBatchPropagator(sunlightRules, sunlightWorldView); - propagators.add(new SunlightRegenBatchPropagator(new SunlightRegenPropagationRules(), regenWorldView, sunlightPropagator, sunlightWorldView)); + propagators.add(new SunlightRegenBatchPropagator(new SunlightRegenPropagationRules(), regenWorldView, + sunlightPropagator, sunlightWorldView)); propagators.add(sunlightPropagator); } public WorldProviderCoreImpl(WorldInfo info, ChunkProvider chunkProvider, Block unloadedBlock, Context context) { - this(info.getTitle(), info.getCustomTitle(), info.getSeed(), info.getTime(), info.getWorldGenerator(), chunkProvider, + this(info.getTitle(), info.getCustomTitle(), info.getSeed(), info.getTime(), info.getWorldGenerator(), + chunkProvider, unloadedBlock, context); } @@ -153,8 +155,8 @@ public ChunkViewCore getLocalView(Vector3ic chunkPos) { } @Override - public ChunkViewCore getWorldViewAround(Vector3i chunk) { - return chunkProvider.getSubviewAroundChunk(chunk); + public ChunkViewCore getWorldViewAround(Vector3ic chunk) { + return chunkProvider.getSubviewAroundChunk(JomlUtil.from(chunk)); } @Override @@ -162,16 +164,6 @@ public boolean isBlockRelevant(int x, int y, int z) { return chunkProvider.isChunkReady(ChunkMath.calcChunkPos(x, y, z)); } - @Override - public boolean isRegionRelevant(Region3i region) { - for (Vector3i chunkPos : ChunkMath.calcChunkPos(region)) { - if (!chunkProvider.isChunkReady(chunkPos)) { - return false; - } - } - return true; - } - @Override public boolean isRegionRelevant(BlockRegionc region) { for (Vector3ic chunkPos : Chunks.toChunkRegion(region, new BlockRegion(BlockRegion.INVALID))) { @@ -182,21 +174,16 @@ public boolean isRegionRelevant(BlockRegionc region) { return true; } - @Override - public Block setBlock(Vector3i worldPos, Block type) { - return this.setBlock(JomlUtil.from(worldPos),type); - } - @Override public Block setBlock(Vector3ic worldPos, Block type) { /* * Hint: This method has a benchmark available in the BenchmarkScreen, The screen can be opened ingame via the * command "showSCreen BenchmarkScreen". */ - Vector3i chunkPos = ChunkMath.calcChunkPos(JomlUtil.from(worldPos)); + Vector3i chunkPos = Chunks.toChunkPos(worldPos, new Vector3i()); CoreChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(JomlUtil.from(worldPos)); + Vector3i blockPos = Chunks.toRelative(worldPos, new Vector3i()); Block oldBlockType = chunk.setBlock(blockPos, type); if (oldBlockType != type) { BlockChange oldChange = blockChanges.get(JomlUtil.from(worldPos)); @@ -205,7 +192,7 @@ public Block setBlock(Vector3ic worldPos, Block type) { } else { oldChange.setTo(type); } - setDirtyChunksNear(JomlUtil.from(worldPos)); + setDirtyChunksNear(worldPos); notifyBlockChanged(worldPos, type, oldBlockType); } return oldBlockType; @@ -215,22 +202,22 @@ public Block setBlock(Vector3ic worldPos, Block type) { } @Override - public Map setBlocks(Map blocks) { + public Map setBlocks(Map blocks) { /* * Hint: This method has a benchmark available in the BenchmarkScreen, The screen can be opened ingame via the * command "showSCreen BenchmarkScreen". */ Set changedBlocks = new HashSet<>(); - Map result = new HashMap<>(blocks.size()); + Map result = new HashMap<>(blocks.size()); - for (Map.Entry entry : blocks.entrySet()) { - Vector3i worldPos = entry.getKey(); - Vector3i chunkPos = ChunkMath.calcChunkPos(worldPos); + for (Map.Entry entry : blocks.entrySet()) { + org.terasology.math.geom.Vector3i worldPos = entry.getKey(); + org.terasology.math.geom.Vector3i chunkPos = ChunkMath.calcChunkPos(worldPos); CoreChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { Block type = entry.getValue(); - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(worldPos); + org.terasology.math.geom.Vector3i blockPos = ChunkMath.calcRelativeBlockPos(worldPos); Block oldBlockType = chunk.setBlock(blockPos, type); if (oldBlockType != type) { BlockChange oldChange = blockChanges.get(worldPos); @@ -239,7 +226,7 @@ public Map setBlocks(Map blocks) { } else { oldChange.setTo(type); } - setDirtyChunksNear(worldPos); + setDirtyChunksNear(JomlUtil.from(worldPos)); changedBlocks.add(new BlockChange(JomlUtil.from(worldPos), oldBlockType, type)); } result.put(worldPos, oldBlockType); @@ -255,8 +242,9 @@ public Map setBlocks(Map blocks) { return result; } - private void setDirtyChunksNear(Vector3i pos0) { - for (Vector3i pos : ChunkMath.getChunkRegionAroundWorldPos(pos0, 1)) { + private void setDirtyChunksNear(Vector3ic worldPos) { + BlockRegion tmpRegion = new BlockRegion(worldPos).expand(1, 1, 1); + for (Vector3ic pos : Chunks.toChunkRegion(tmpRegion, tmpRegion)) { RenderableChunk dirtiedChunk = chunkProvider.getChunk(pos); if (dirtiedChunk != null) { dirtiedChunk.setDirty(true); @@ -285,66 +273,68 @@ private void notifyExtraDataChanged(int index, Vector3ic pos, int newData, int o @Override public Block getBlock(int x, int y, int z) { - CoreChunk chunk = chunkProvider.getChunk(ChunkMath.calcChunkPosX(x), ChunkMath.calcChunkPosY(y), ChunkMath.calcChunkPosZ(z)); + CoreChunk chunk = chunkProvider.getChunk(Chunks.toChunkPos(x, y, z, new Vector3i())); if (chunk != null) { - return chunk.getBlock(ChunkMath.calcBlockPosX(x), ChunkMath.calcBlockPosY(y), ChunkMath.calcBlockPosZ(z)); + return chunk.getBlock(Chunks.toRelativeX(x), Chunks.toRelativeX(y), Chunks.toRelativeX(z)); } return unloadedBlock; } @Override public byte getLight(int x, int y, int z) { - Vector3i chunkPos = ChunkMath.calcChunkPos(x, y, z); + Vector3i chunkPos = Chunks.toChunkPos(x, y, z, new Vector3i()); LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(x, y, z); - return chunk.getLight(blockPos); + Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); + return chunk.getLight(JomlUtil.from(blockPos)); } return 0; } @Override public byte getSunlight(int x, int y, int z) { - Vector3i chunkPos = ChunkMath.calcChunkPos(x, y, z); + Vector3i chunkPos = Chunks.toChunkPos(x, y, z, new Vector3i()); LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(x, y, z); - return chunk.getSunlight(blockPos); + Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); + return chunk.getSunlight(JomlUtil.from(blockPos)); } return 0; } @Override public byte getTotalLight(int x, int y, int z) { - Vector3i chunkPos = ChunkMath.calcChunkPos(x, y, z); + Vector3i chunkPos = Chunks.toChunkPos(x, y, z, new Vector3i()); LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(x, y, z); - return (byte) Math.max(chunk.getSunlight(blockPos), chunk.getLight(blockPos)); + Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); + return (byte) Math.max(chunk.getSunlight(JomlUtil.from(blockPos)), chunk.getLight(JomlUtil.from(blockPos))); } return 0; } @Override public int getExtraData(int index, int x, int y, int z) { - CoreChunk chunk = chunkProvider.getChunk(ChunkMath.calcChunkPosX(x), ChunkMath.calcChunkPosY(y), ChunkMath.calcChunkPosZ(z)); + CoreChunk chunk = chunkProvider.getChunk(ChunkMath.calcChunkPosX(x), ChunkMath.calcChunkPosY(y), + ChunkMath.calcChunkPosZ(z)); if (chunk != null) { - return chunk.getExtraData(index, ChunkMath.calcBlockPosX(x), ChunkMath.calcBlockPosY(y), ChunkMath.calcBlockPosZ(z)); + return chunk.getExtraData(index, ChunkMath.calcBlockPosX(x), ChunkMath.calcBlockPosY(y), + ChunkMath.calcBlockPosZ(z)); } return 0; } @Override - public int setExtraData(int index, Vector3i worldPos, int value) { - Vector3i chunkPos = ChunkMath.calcChunkPos(worldPos); + public int setExtraData(int index, Vector3ic worldPos, int value) { + org.joml.Vector3i chunkPos = Chunks.toChunkPos(worldPos, new org.joml.Vector3i()); CoreChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { - Vector3i blockPos = ChunkMath.calcRelativeBlockPos(worldPos); + org.joml.Vector3i blockPos = Chunks.toRelative(worldPos, new org.joml.Vector3i()); int oldValue = chunk.getExtraData(index, blockPos.x, blockPos.y, blockPos.z); chunk.setExtraData(index, blockPos.x, blockPos.y, blockPos.z, value); if (oldValue != value) { setDirtyChunksNear(worldPos); - notifyExtraDataChanged(index, JomlUtil.from(worldPos), value, oldValue); + notifyExtraDataChanged(index, worldPos, value, oldValue); } return oldValue; } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java index 6786e421d2f..f0c50b1a9c4 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderWrapper.java @@ -16,18 +16,16 @@ package org.terasology.world.internal; +import org.joml.RoundingMode; import org.joml.Vector3fc; +import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.world.WorldChangeListener; import org.terasology.world.WorldProvider; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; -import java.math.RoundingMode; import java.util.Collection; /** @@ -42,29 +40,14 @@ public WorldProviderWrapper(WorldProviderCore core, ExtraBlockDataManager extraD this.extraDataManager = extraDataManager; } - @Override - public boolean isBlockRelevant(Vector3i pos) { - return core.isBlockRelevant(pos.x, pos.y, pos.z); - } - @Override public boolean isBlockRelevant(Vector3ic pos) { return core.isBlockRelevant(pos.x(), pos.y(), pos.z()); } - @Override - public boolean isBlockRelevant(Vector3f pos) { - return isBlockRelevant(new Vector3i(pos, RoundingMode.HALF_UP)); - } - @Override public boolean isBlockRelevant(Vector3fc pos) { - return isBlockRelevant(new org.joml.Vector3i(pos, org.joml.RoundingMode.HALF_UP)); - } - - @Override - public Block setBlock(Vector3i pos, Block type) { - return core.setBlock(pos, type); + return isBlockRelevant(new Vector3i(pos, RoundingMode.HALF_UP)); } @Override @@ -72,59 +55,39 @@ public Block setBlock(Vector3ic pos, Block type) { return core.setBlock(pos, type); } - @Override - public Block getBlock(Vector3f pos) { - return getBlock(new Vector3i(pos, RoundingMode.HALF_UP)); - } - @Override public Block getBlock(Vector3fc pos) { - return getBlock(new org.joml.Vector3i(pos, org.joml.RoundingMode.HALF_UP)); - } - - @Override - public Block getBlock(Vector3i pos) { - return core.getBlock(pos.x, pos.y, pos.z); - } - - @Override - public Block getBlock(Vector3ic pos) { - return core.getBlock(pos.x(), pos.y(), pos.z()); + return getBlock(new Vector3i(pos, RoundingMode.HALF_UP)); } @Override - public byte getLight(Vector3i pos) { - return core.getLight(pos.x, pos.y, pos.z); + public byte getLight(Vector3ic pos) { + return core.getLight(pos.x(), pos.y(), pos.z()); } @Override - public byte getLight(Vector3f pos) { - return getLight(new Vector3i(pos, RoundingMode.HALF_UP)); + public byte getLight(Vector3fc pos) { + return getLight(new Vector3i(pos, RoundingMode.FLOOR)); } @Override - public byte getSunlight(Vector3f pos) { + public byte getSunlight(Vector3fc pos) { return getSunlight(new Vector3i(pos, RoundingMode.HALF_UP)); } @Override - public byte getTotalLight(Vector3f pos) { + public byte getTotalLight(Vector3fc pos) { return getTotalLight(new Vector3i(pos, RoundingMode.HALF_UP)); } - @Override - public byte getSunlight(Vector3i pos) { - return core.getSunlight(pos.x, pos.y, pos.z); + public byte getSunlight(Vector3ic pos) { + return core.getSunlight(pos.x(), pos.y(), pos.z()); } @Override - public byte getTotalLight(Vector3i pos) { - return core.getTotalLight(pos.x, pos.y, pos.z); - } - - public int getExtraData(int index, Vector3i pos) { - return core.getExtraData(index, pos.x, pos.y, pos.z); + public byte getTotalLight(Vector3ic pos) { + return core.getTotalLight(pos.x(), pos.y(), pos.z()); } public int setExtraData(int index, int x, int y, int z, int value) { @@ -135,15 +98,11 @@ public int getExtraData(String fieldName, int x, int y, int z) { return core.getExtraData(extraDataManager.getSlotNumber(fieldName), x, y, z); } - public int getExtraData(String fieldName, Vector3i pos) { - return core.getExtraData(extraDataManager.getSlotNumber(fieldName), pos.x, pos.y, pos.z); - } - public int setExtraData(String fieldName, int x, int y, int z, int value) { return core.setExtraData(extraDataManager.getSlotNumber(fieldName), new Vector3i(x, y, z), value); } - public int setExtraData(String fieldName, Vector3i pos, int value) { + public int setExtraData(String fieldName, Vector3ic pos, int value) { return core.setExtraData(extraDataManager.getSlotNumber(fieldName), pos, value); } From 7189173ca1c973b37f75a30a818cb77ee9e57171 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 14:37:57 -0800 Subject: [PATCH 128/259] chore (build): keep jars in "libs/" not "lib/" in distForLauncher --- facades/PC/build.gradle.kts | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 9ffbcb80823..b3d7f350006 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -247,7 +247,44 @@ tasks.register("distForLauncher") { archiveFileName.set("Terasology.zip") // Launcher expects `libs/Terasology.jar`, no containing folder - this.with(distributions.getByName("main").contents) + // TODO: fix launcher so it can take either structure. It should be able to do without ambiguity. + val defaultLibraryDirectory = "lib" + val launcherLibraryDirectory = "libs" + + this.with(distributions.getByName("main").contents { + eachFile { + val pathSegments = relativePath.segments + + when (pathSegments[0]) { + defaultLibraryDirectory -> { + // Redirect things from lib/ to libs/ + val tail = pathSegments.sliceArray(1 until pathSegments.size) + relativePath = RelativePath(true, launcherLibraryDirectory, *tail) + } + + application.executableDir -> { + // I don't know how the "lib/" makes its way in to the classpath used by CreateStartScripts, + // so we're adjusting it after-the-fact. + filter(ScriptClasspathRewriter(this, defaultLibraryDirectory, launcherLibraryDirectory)) + } + } + } + }) +} + +class ScriptClasspathRewriter(file: FileCopyDetails, val oldDirectory: String, val newDirectory: String) : Transformer { + private val isBatchFile = file.name.endsWith(".bat") + private val assignment = if (isBatchFile) "set CLASSPATH=" else "CLASSPATH=" + + override fun transform(line: String): String = if (line.startsWith(assignment)) { + if (isBatchFile) { + line.replace("\\$oldDirectory\\", "\\$newDirectory\\") + } else { + line.replace("/$oldDirectory/", "/$newDirectory/") + } + } else { + line + } } // NOTE: If you build a distribution while you have modules, all the test dependencies are in here. From bb3c6c161525bc836264f8a75d289b8dd30fe3cb Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 14:53:11 -0800 Subject: [PATCH 129/259] fix (build): do not ignore build output appearing in a source directory engine:processResources has been adjusted so this file needn't end up there. --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index f463d908391..8a2ad06e8af 100644 --- a/.gitignore +++ b/.gitignore @@ -62,9 +62,6 @@ Icon ehthumbs.db Thumbs.db -# Ignore Terasology build output -/engine/src/main/resources/Credits.md - # Ignore Terasology output *.log /saves/ From ea923c357d661e0553b371d5ae966e95b1f6af9c Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Mon, 18 Jan 2021 00:02:28 +0100 Subject: [PATCH 130/259] build(jmh): git-ignore generated code and use updated config zip to avoid warnings in SpotBugs (#4406) Co-authored-by: Cervator --- .gitignore | 3 +++ build.gradle | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f463d908391..2dda0305afe 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ !.gitignore !.github +# Ignore generated code +/engine/src/jmh/generated + # Ignore subdirs with their own Git roots. PC Facade and Core module are bundled with the main repo. extensions /facades/* diff --git a/build.gradle b/build.gradle index c986c48c023..9eb52e23993 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,7 @@ dependencies { // Config for our code analytics lives in a centralized repo: https://github.com/MovingBlocks/TeraConfig - codeMetrics group: 'org.terasology.config', name: 'codemetrics', version: '1.3.2', ext: 'zip' + codeMetrics group: 'org.terasology.config', name: 'codemetrics', version: '1.6.0', ext: 'zip' // Natives for JNLua (Kallisti, KComputers) natives group: 'org.terasology.jnlua', name: 'jnlua_natives', version: '0.1.0-SNAPSHOT', ext: 'zip' From 474a312704dfd521819b5c9fff06a9d1cf4dd02a Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 15:06:07 -0800 Subject: [PATCH 131/259] chore (build): remove unused var --- facades/PC/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index b3d7f350006..a3dba27512d 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -49,7 +49,6 @@ val localServerDataPath by extra("terasology-server") // General props val mainClassName by extra("org.terasology.engine.Terasology") -val subDirLibs = "libs" val templatesDir = File(rootDir, "templates") val rootDirDist = File(rootDir, "build/distributions") From a4a966514f22d9cf1ff88fd248d782e9837767f0 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 17 Jan 2021 16:08:03 -0800 Subject: [PATCH 132/259] chore (build): leave dateTime out of locally-built versionInfo To avoid gradle deciding that engine's build is always stale. --- engine/build.gradle | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/engine/build.gradle b/engine/build.gradle index b04e23b1f05..f6b6e440703 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -238,10 +238,18 @@ def createVersionInfoFile = tasks.register("createVersionInfoFile", WritePropert jobName: env.JOB_NAME, gitBranch: convertGitBranch(env.GIT_BRANCH), gitCommit: env.GIT_COMMIT, - dateTime: startDateTimeString, displayVersion: displayVersion, engineVersion: version ].findAll { it.value != null }) + if (env.JOB_NAME != null) { + // Only set the dateTime property when there is a Jenkins JOB_NAME. + // It is a value we can always get (on Jenkins or otherwise) but we don't want local builds + // to invalidate their cache whenever the time changes. + // TODO: after upgrading to Gradle 6.8, see if we can have it ignore this property specifically: + // https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:property_file_normalization + property("dateTime", startDateTimeString) + } + outputFile = "$buildDir/createVersionInfoFile/versionInfo.properties" } From 6ed5afa5b59d60ce8d29347633333b797e567b62 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 18 Jan 2021 15:14:47 -0800 Subject: [PATCH 133/259] feat(JOML): migrate joml to 1.10.0 and 1.0.0-SNAPSHOT for geometry (#4413) * feat(JOML): migrate joml to 1.10.0 and 1.0.0-SNAPSHOT for geometry * build: use TeraNUI 1.4.0-SNAPSHOT (with JOML 1.10 and joml-geom) Co-authored-by: Tobias Nett --- .../typeHandling/mathTypes/AABBTypeHandlerTest.java | 4 ++-- .../mathTypes/BlockRegionTypeHandlerTest.java | 2 +- .../rendering/nui/layouts/ZoomableLayoutTest.java | 4 ++-- .../org/terasology/world/block/BlockRegionTest.java | 8 ++++---- engine/build.gradle | 11 ++++++----- .../subsystem/headless/assets/HeadlessTexture.java | 4 ++-- .../headless/renderer/HeadlessCanvasRenderer.java | 2 +- .../org/terasology/logic/behavior/nui/PortList.java | 2 +- engine/src/main/java/org/terasology/math/AABB.java | 2 +- .../src/main/java/org/terasology/math/JomlUtil.java | 6 +++--- .../typeHandling/TypeHandlerLibraryImpl.java | 4 ++-- .../typeHandling/mathTypes/AABBfTypeHandler.java | 4 ++-- .../typeHandling/mathTypes/AABBiTypeHandler.java | 2 +- .../mathTypes/RectanglefTypeHandler.java | 2 +- .../mathTypes/RectangleiTypeHandler.java | 2 +- .../main/java/org/terasology/physics/Physics.java | 2 +- .../org/terasology/physics/bullet/BulletPhysics.java | 2 +- .../physics/bullet/shapes/BulletCollisionShape.java | 2 +- .../terasology/physics/shapes/CollisionShape.java | 2 +- .../rendering/assets/texture/BasicTextureRegion.java | 4 ++-- .../rendering/assets/texture/TextureRegion.java | 4 ++-- .../rendering/assets/texture/TextureUtil.java | 2 +- .../assets/texture/subtexture/Subtexture.java | 4 ++-- .../org/terasology/rendering/cameras/Camera.java | 2 +- .../terasology/rendering/cameras/ViewFrustum.java | 2 +- .../rendering/iconmesh/IconMeshFactory.java | 2 +- .../org/terasology/rendering/logic/MeshRenderer.java | 2 +- .../terasology/rendering/nui/CoreScreenLayer.java | 2 +- .../nui/animation/DeferredMenuAnimationSystem.java | 2 +- .../rendering/nui/animation/MenuAnimationSystem.java | 2 +- .../nui/animation/MenuAnimationSystemStub.java | 2 +- .../nui/animation/SwipeMenuAnimationSystem.java | 2 +- .../rendering/nui/contextMenu/ContextMenuScreen.java | 2 +- .../rendering/nui/internal/LwjglCanvasRenderer.java | 4 ++-- .../rendering/nui/internal/TerasologyCanvasImpl.java | 2 +- .../nui/internal/TerasologyCanvasRenderer.java | 2 +- .../rendering/nui/layers/hud/HUDScreenLayer.java | 2 +- .../browser/data/basic/FlowParagraphRenderable.java | 2 +- .../data/basic/flow/ContainerRenderSpace.java | 2 +- .../browser/data/basic/flow/FlowRenderable.java | 2 +- .../browser/data/basic/flow/ImageFlowRenderable.java | 2 +- .../browser/data/basic/flow/TextFlowRenderable.java | 2 +- .../data/html/basic/list/OrderedListDecorator.java | 2 +- .../data/html/basic/list/UnorderedListDecorator.java | 2 +- .../nui/widgets/browser/ui/BrowserWidget.java | 2 +- .../ui/ContainerFlowContainerRenderSpace.java | 2 +- .../nui/widgets/browser/ui/DocumentRenderer.java | 2 +- .../nui/widgets/browser/ui/ParagraphRenderable.java | 2 +- .../terasology/rendering/opengl/OpenGLTexture.java | 4 ++-- .../main/java/org/terasology/world/block/Block.java | 2 +- .../java/org/terasology/world/block/BlockAreac.java | 2 +- .../org/terasology/world/block/BlockRegionc.java | 12 ++++++------ .../world/block/items/BlockItemSystem.java | 2 +- 53 files changed, 78 insertions(+), 77 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java index 3c92e1b0097..e7d5a81c6d5 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/AABBTypeHandlerTest.java @@ -6,8 +6,8 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.joml.AABBf; -import org.joml.AABBi; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBi; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.reflections.Reflections; diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java index 4dd5e1e5a59..a129610612c 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/mathTypes/BlockRegionTypeHandlerTest.java @@ -6,7 +6,7 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.joml.AABBi; +import org.terasology.joml.geom.AABBi; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.reflections.Reflections; diff --git a/engine-tests/src/test/java/org/terasology/rendering/nui/layouts/ZoomableLayoutTest.java b/engine-tests/src/test/java/org/terasology/rendering/nui/layouts/ZoomableLayoutTest.java index c0ae4107ac1..65ff5fba3ee 100644 --- a/engine-tests/src/test/java/org/terasology/rendering/nui/layouts/ZoomableLayoutTest.java +++ b/engine-tests/src/test/java/org/terasology/rendering/nui/layouts/ZoomableLayoutTest.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.layouts; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.joml.Vector2f; @@ -61,7 +61,7 @@ public void setup() { canvas = mock(Canvas.class); - // + // // +------+ // | 1 | // +------+ diff --git a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java index 7d39a32898a..be1c7ee5cb3 100644 --- a/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/block/BlockRegionTest.java @@ -5,10 +5,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.joml.AABBf; -import org.joml.LineSegmentf; -import org.joml.Rayf; -import org.joml.Spheref; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.LineSegmentf; +import org.terasology.joml.geom.Rayf; +import org.terasology.joml.geom.Spheref; import org.joml.Vector2f; import org.joml.Vector3f; import org.joml.Vector3fc; diff --git a/engine/build.gradle b/engine/build.gradle index 6b17fd89528..ac56eddbf21 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -95,8 +95,9 @@ dependencies { api "org.lwjgl:lwjgl-opengl" implementation "org.lwjgl:lwjgl-stb" - api group: 'java3d', name: 'vecmath', version: '1.3.1' - api group: 'org.joml', name: 'joml', version: '1.9.25' + api group: 'org.joml', name: 'joml', version: '1.10.0' + api group: 'org.terasology.joml-ext', name: 'joml-geometry', version: '1.0.0-SNAPSHOT' + implementation group: 'org.abego.treelayout', name: 'org.abego.treelayout.core', version: '1.0.3' api group: 'com.miglayout', name: 'miglayout-core', version: '5.0' implementation group: 'de.matthiasmann.twl', name: 'PNGDecoder', version: '1111' @@ -128,8 +129,8 @@ dependencies { api group: 'org.terasology', name: 'splash-screen', version: '1.1.1' api group: 'org.terasology.jnlua', name: 'JNLua', version: '0.1.0-SNAPSHOT' api group: 'org.terasology.jnbullet', name: 'JNBullet', version: '1.0.2' - api group: 'org.terasology.nui', name: 'nui', version: '1.3.1' - api group: 'org.terasology.nui', name: 'nui-reflect', version: '1.3.1' + api group: 'org.terasology.nui', name: 'nui', version: '1.4.0-SNAPSHOT' + api group: 'org.terasology.nui', name: 'nui-reflect', version: '1.4.0-SNAPSHOT' // Wildcard dependency to catch any libs provided with the project (remote repo preferred instead) api fileTree(dir: 'libs', include: '*.jar') @@ -139,7 +140,7 @@ dependencies { // TODO: Consider moving this back to the PC Facade instead of having the engine rely on it? implementation group: 'org.terasology.crashreporter', name: 'cr-terasology', version: '4.1.0' - + api(project(":subsystems:TypeHandlerLibrary")) } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java index b2d927b1385..acca5a6cdd6 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java @@ -16,8 +16,8 @@ package org.terasology.engine.subsystem.headless.assets; import com.google.common.collect.Lists; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessCanvasRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessCanvasRenderer.java index 71927dc1be7..3244acbadc6 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessCanvasRenderer.java @@ -4,7 +4,7 @@ package org.terasology.engine.subsystem.headless.renderer; import org.joml.Quaternionfc; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.joml.Vector2ic; import org.joml.Vector3fc; diff --git a/engine/src/main/java/org/terasology/logic/behavior/nui/PortList.java b/engine/src/main/java/org/terasology/logic/behavior/nui/PortList.java index 6f185dff79b..26360690137 100644 --- a/engine/src/main/java/org/terasology/logic/behavior/nui/PortList.java +++ b/engine/src/main/java/org/terasology/logic/behavior/nui/PortList.java @@ -16,7 +16,7 @@ package org.terasology.logic.behavior.nui; import com.google.common.collect.Lists; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.Canvas; import java.util.ArrayList; diff --git a/engine/src/main/java/org/terasology/math/AABB.java b/engine/src/main/java/org/terasology/math/AABB.java index a4ba46708d8..1fbead9943d 100644 --- a/engine/src/main/java/org/terasology/math/AABB.java +++ b/engine/src/main/java/org/terasology/math/AABB.java @@ -30,7 +30,7 @@ /** * An axis-aligned bounding box. Provides basic support for inclusion and intersection tests. * @deprecated this class is schedules for removal in an upcoming version - * Use the JOML implementation instead: {@link org.joml.AABBf} + * Use the JOML implementation instead: {@link org.terasology.joml.geom.AABBf} **/ @Deprecated public final class AABB { diff --git a/engine/src/main/java/org/terasology/math/JomlUtil.java b/engine/src/main/java/org/terasology/math/JomlUtil.java index 4df4a000451..009912da8d1 100644 --- a/engine/src/main/java/org/terasology/math/JomlUtil.java +++ b/engine/src/main/java/org/terasology/math/JomlUtil.java @@ -15,14 +15,14 @@ */ package org.terasology.math; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Matrix3f; import org.joml.Matrix3fc; import org.joml.Matrix4fc; import org.joml.Quaternionf; import org.joml.Quaternionfc; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2fc; import org.joml.Vector2ic; import org.joml.Vector3fc; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java index 4cce55ef3e3..44c1732c2c1 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/TypeHandlerLibraryImpl.java @@ -3,8 +3,8 @@ package org.terasology.persistence.typeHandling; -import org.joml.AABBf; -import org.joml.AABBi; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBi; import org.joml.Quaternionf; import org.joml.Quaternionfc; import org.joml.Vector2fc; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBfTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBfTypeHandler.java index 66e4962f030..a9cf3310fc3 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBfTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBfTypeHandler.java @@ -6,8 +6,8 @@ import com.google.common.collect.Maps; import gnu.trove.list.TFloatList; import gnu.trove.list.TIntList; -import org.joml.AABBf; -import org.joml.AABBi; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBi; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataArray; import org.terasology.persistence.typeHandling.PersistedDataMap; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBiTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBiTypeHandler.java index ace5173ac88..3acbff7870c 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBiTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/AABBiTypeHandler.java @@ -5,7 +5,7 @@ import com.google.common.collect.Maps; import gnu.trove.list.TIntList; -import org.joml.AABBi; +import org.terasology.joml.geom.AABBi; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataArray; import org.terasology.persistence.typeHandling.PersistedDataMap; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java index 43c499ea0c0..bf812840d90 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectanglefTypeHandler.java @@ -5,7 +5,7 @@ import com.google.common.collect.Maps; import gnu.trove.list.TFloatList; -import org.joml.Rectanglef; +import org.terasology.joml.geom.Rectanglef; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataArray; import org.terasology.persistence.typeHandling.PersistedDataMap; diff --git a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java index ef8ede84145..5e022597258 100644 --- a/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java +++ b/engine/src/main/java/org/terasology/persistence/typeHandling/mathTypes/RectangleiTypeHandler.java @@ -5,7 +5,7 @@ import com.google.common.collect.Maps; import gnu.trove.list.TIntList; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.persistence.typeHandling.PersistedData; import org.terasology.persistence.typeHandling.PersistedDataArray; import org.terasology.persistence.typeHandling.PersistedDataMap; diff --git a/engine/src/main/java/org/terasology/physics/Physics.java b/engine/src/main/java/org/terasology/physics/Physics.java index bfd81db3a1f..c6787f81676 100644 --- a/engine/src/main/java/org/terasology/physics/Physics.java +++ b/engine/src/main/java/org/terasology/physics/Physics.java @@ -15,7 +15,7 @@ */ package org.terasology.physics; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Vector3f; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.AABB; diff --git a/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java b/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java index 47db703c2b8..4212db6e4e9 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java +++ b/engine/src/main/java/org/terasology/physics/bullet/BulletPhysics.java @@ -34,7 +34,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import gnu.trove.iterator.TFloatIterator; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; diff --git a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCollisionShape.java b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCollisionShape.java index 4641c10f745..defe33dfc13 100644 --- a/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCollisionShape.java +++ b/engine/src/main/java/org/terasology/physics/bullet/shapes/BulletCollisionShape.java @@ -17,7 +17,7 @@ import com.badlogic.gdx.physics.bullet.collision.btCollisionShape; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Matrix4f; import org.joml.Quaternionfc; import org.joml.Vector3f; diff --git a/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java b/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java index 5430622c770..1d768e4568d 100644 --- a/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java +++ b/engine/src/main/java/org/terasology/physics/shapes/CollisionShape.java @@ -15,7 +15,7 @@ */ package org.terasology.physics.shapes; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Quaternionf; import org.joml.Quaternionfc; import org.joml.Vector3fc; diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java b/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java index 58dc66be382..20151284e5a 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/BasicTextureRegion.java @@ -15,8 +15,8 @@ */ package org.terasology.rendering.assets.texture; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2fc; import org.joml.Vector2i; import org.terasology.math.JomlUtil; diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/TextureRegion.java b/engine/src/main/java/org/terasology/rendering/assets/texture/TextureRegion.java index a15aaa9146a..45fce9e2b28 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/TextureRegion.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/TextureRegion.java @@ -15,8 +15,8 @@ */ package org.terasology.rendering.assets.texture; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; /** diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/TextureUtil.java b/engine/src/main/java/org/terasology/rendering/assets/texture/TextureUtil.java index a1fc9547958..3a00c670380 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/TextureUtil.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/TextureUtil.java @@ -17,7 +17,7 @@ package org.terasology.rendering.assets.texture; import com.google.common.primitives.UnsignedBytes; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.assets.ResourceUrn; import org.terasology.engine.TerasologyConstants; import org.terasology.naming.Name; diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/Subtexture.java b/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/Subtexture.java index 88a7498ab01..b6ac79c21ab 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/Subtexture.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/Subtexture.java @@ -15,8 +15,8 @@ */ package org.terasology.rendering.assets.texture.subtexture; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.Asset; import org.terasology.assets.AssetType; diff --git a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java index 01c724e10b0..6afaf5553d4 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.cameras; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.AxisAngle4f; import org.joml.Matrix4f; import org.joml.Quaternionf; diff --git a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java index a06d27faabd..ecaedeb5ead 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.cameras; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Vector3fc; import org.lwjgl.BufferUtils; import org.terasology.logic.players.LocalPlayer; diff --git a/engine/src/main/java/org/terasology/rendering/iconmesh/IconMeshFactory.java b/engine/src/main/java/org/terasology/rendering/iconmesh/IconMeshFactory.java index db8f7cba5d8..101491cea8d 100644 --- a/engine/src/main/java/org/terasology/rendering/iconmesh/IconMeshFactory.java +++ b/engine/src/main/java/org/terasology/rendering/iconmesh/IconMeshFactory.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.iconmesh; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector4f; import org.terasology.math.JomlUtil; import org.terasology.utilities.Assets; diff --git a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java index e51cc320823..a2f1db4cc3c 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java @@ -17,7 +17,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Quaternionf; diff --git a/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java b/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java index e82631442e9..b31eba0dbac 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/CoreScreenLayer.java @@ -3,7 +3,7 @@ package org.terasology.rendering.nui; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.ResourceUrn; import org.terasology.input.ButtonState; diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java index a7b75f9a807..06b21770923 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/DeferredMenuAnimationSystem.java @@ -18,7 +18,7 @@ import java.util.function.Supplier; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.math.geom.Rect2i; /** diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java index b1cc4af2a00..cbb8f4e89a8 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystem.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.animation; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; /** * Controls animations to and from different screens diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java index cb1c9cbcbb9..bd0194ed93c 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/MenuAnimationSystemStub.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.animation; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; /** * Does not do anything. The {@link #onEnd(Runnable)} method is triggered instantly. diff --git a/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java b/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java index 8ebc91a62ae..b51d24c1c52 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java +++ b/engine/src/main/java/org/terasology/rendering/nui/animation/SwipeMenuAnimationSystem.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.animation; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.math.geom.Rect2i; import org.terasology.rendering.animation.Animation; import org.terasology.rendering.animation.AnimationListener; diff --git a/engine/src/main/java/org/terasology/rendering/nui/contextMenu/ContextMenuScreen.java b/engine/src/main/java/org/terasology/rendering/nui/contextMenu/ContextMenuScreen.java index ae537b2d09f..5d196017ea5 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/contextMenu/ContextMenuScreen.java +++ b/engine/src/main/java/org/terasology/rendering/nui/contextMenu/ContextMenuScreen.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.contextMenu; import com.google.common.collect.Lists; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.ResourceUrn; import org.terasology.math.JomlUtil; diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java index 19d91e0889e..393efbd77fc 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java @@ -8,8 +8,8 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Quaternionfc; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2f; import org.joml.Vector2ic; import org.joml.Vector3f; diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java index 1944d66e11e..2b0b2943376 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.nui.internal; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasRenderer.java index 18d467f40a9..aad6ad4036a 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasRenderer.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.internal; import org.joml.Quaternionfc; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2ic; import org.joml.Vector3fc; import org.terasology.assets.ResourceUrn; diff --git a/engine/src/main/java/org/terasology/rendering/nui/layers/hud/HUDScreenLayer.java b/engine/src/main/java/org/terasology/rendering/nui/layers/hud/HUDScreenLayer.java index 4b0163ad8de..f32e7afbab0 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/layers/hud/HUDScreenLayer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/layers/hud/HUDScreenLayer.java @@ -16,7 +16,7 @@ package org.terasology.rendering.nui.layers.hud; import com.google.common.collect.Maps; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/FlowParagraphRenderable.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/FlowParagraphRenderable.java index daa189175be..ff7a974199e 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/FlowParagraphRenderable.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/FlowParagraphRenderable.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.basic; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.Canvas; import org.terasology.nui.HorizontalAlign; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ContainerRenderSpace.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ContainerRenderSpace.java index f36f624d054..429274a20de 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ContainerRenderSpace.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ContainerRenderSpace.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.basic.flow; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.rendering.nui.widgets.browser.ui.style.ParagraphRenderStyle; public interface ContainerRenderSpace { diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/FlowRenderable.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/FlowRenderable.java index 0d0b14a605d..1f1b8c9a670 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/FlowRenderable.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/FlowRenderable.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.basic.flow; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.Canvas; import org.terasology.rendering.nui.widgets.browser.ui.style.TextRenderStyle; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ImageFlowRenderable.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ImageFlowRenderable.java index 0fd40aab339..c67ca913eea 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ImageFlowRenderable.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/ImageFlowRenderable.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.basic.flow; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.Canvas; import org.terasology.nui.UITextureRegion; import org.terasology.rendering.nui.widgets.browser.ui.style.TextRenderStyle; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/TextFlowRenderable.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/TextFlowRenderable.java index 36cfa6d3023..79e97b15da8 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/TextFlowRenderable.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/basic/flow/TextFlowRenderable.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.basic.flow; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.math.JomlUtil; import org.terasology.nui.Canvas; import org.terasology.nui.asset.font.Font; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/OrderedListDecorator.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/OrderedListDecorator.java index 152351bfa38..b1d359b62de 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/OrderedListDecorator.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/OrderedListDecorator.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.html.basic.list; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.Canvas; import org.terasology.nui.HorizontalAlign; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/UnorderedListDecorator.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/UnorderedListDecorator.java index 61c5844ac01..63ca9d0e31b 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/UnorderedListDecorator.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/data/html/basic/list/UnorderedListDecorator.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.data.html.basic.list; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.Canvas; import org.terasology.nui.HorizontalAlign; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/BrowserWidget.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/BrowserWidget.java index d9cf6feb63f..c48488ff8fd 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/BrowserWidget.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/BrowserWidget.java @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.nui.widgets.browser.ui; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.BaseInteractionListener; import org.terasology.nui.Canvas; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ContainerFlowContainerRenderSpace.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ContainerFlowContainerRenderSpace.java index 9b36ff53a55..5785b72f276 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ContainerFlowContainerRenderSpace.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ContainerFlowContainerRenderSpace.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.ui; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.util.RectUtility; import org.terasology.rendering.nui.widgets.browser.data.basic.flow.ContainerRenderSpace; import org.terasology.rendering.nui.widgets.browser.ui.style.ParagraphRenderStyle; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/DocumentRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/DocumentRenderer.java index 8cbcab02c3e..508fbce1b11 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/DocumentRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/DocumentRenderer.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.ui; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.Canvas; import org.terasology.nui.Color; diff --git a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ParagraphRenderable.java b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ParagraphRenderable.java index 623427605f4..5f1bc7a3b89 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ParagraphRenderable.java +++ b/engine/src/main/java/org/terasology/rendering/nui/widgets/browser/ui/ParagraphRenderable.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.nui.widgets.browser.ui; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.nui.Canvas; import org.terasology.nui.HorizontalAlign; diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java index fc44640382f..3609802b277 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java @@ -16,8 +16,8 @@ package org.terasology.rendering.opengl; import com.google.common.collect.Lists; -import org.joml.Rectanglef; -import org.joml.Rectanglei; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/engine/src/main/java/org/terasology/world/block/Block.java b/engine/src/main/java/org/terasology/world/block/Block.java index 2f06038119e..a01b89c84c7 100644 --- a/engine/src/main/java/org/terasology/world/block/Block.java +++ b/engine/src/main/java/org/terasology/world/block/Block.java @@ -16,7 +16,7 @@ package org.terasology.world.block; import com.google.common.collect.Maps; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Quaternionf; import org.joml.RoundingMode; import org.joml.Vector3f; diff --git a/engine/src/main/java/org/terasology/world/block/BlockAreac.java b/engine/src/main/java/org/terasology/world/block/BlockAreac.java index eaaaf40da29..1951743f585 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockAreac.java +++ b/engine/src/main/java/org/terasology/world/block/BlockAreac.java @@ -3,7 +3,7 @@ package org.terasology.world.block; -import org.joml.Rectanglef; +import org.terasology.joml.geom.Rectanglef; import org.joml.Vector2f; import org.joml.Vector2fc; import org.joml.Vector2i; diff --git a/engine/src/main/java/org/terasology/world/block/BlockRegionc.java b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java index 837e64b9d10..4f0a192c9e5 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockRegionc.java +++ b/engine/src/main/java/org/terasology/world/block/BlockRegionc.java @@ -2,13 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block; -import org.joml.AABBf; -import org.joml.Intersectionf; -import org.joml.LineSegmentf; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.Intersectionf; +import org.terasology.joml.geom.LineSegmentf; import org.joml.Matrix4fc; -import org.joml.Planef; -import org.joml.Rayf; -import org.joml.Spheref; +import org.terasology.joml.geom.Planef; +import org.terasology.joml.geom.Rayf; +import org.terasology.joml.geom.Spheref; import org.joml.Vector2f; import org.joml.Vector3f; import org.joml.Vector3fc; diff --git a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java index 158946e60aa..cfa422e4006 100644 --- a/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java +++ b/engine/src/main/java/org/terasology/world/block/items/BlockItemSystem.java @@ -15,7 +15,7 @@ */ package org.terasology.world.block.items; -import org.joml.AABBf; +import org.terasology.joml.geom.AABBf; import org.joml.Vector2f; import org.joml.Vector3fc; import org.joml.Vector3i; From 3a678f8135df9e323b45d60c90139c3a401cd455 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:19:09 -0800 Subject: [PATCH 134/259] chore (build): initial import of start scripts as distributed by gradle from https://github.com/gradle/gradle/tree/f38a522/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins --- .../src/main/startScripts/unixStartScript.txt | 185 ++++++++++++++++++ .../main/startScripts/windowsStartScript.txt | 90 +++++++++ 2 files changed, 275 insertions(+) create mode 100644 facades/PC/src/main/startScripts/unixStartScript.txt create mode 100644 facades/PC/src/main/startScripts/windowsStartScript.txt diff --git a/facades/PC/src/main/startScripts/unixStartScript.txt b/facades/PC/src/main/startScripts/unixStartScript.txt new file mode 100644 index 00000000000..505325e09f2 --- /dev/null +++ b/facades/PC/src/main/startScripts/unixStartScript.txt @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## ${applicationName} start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: \$0 may be a link +PRG="\$0" +# Need this for relative symlinks. +while [ -h "\$PRG" ] ; do + ls=`ls -ld "\$PRG"` + link=`expr "\$ls" : '.*-> \\(.*\\)\$'` + if expr "\$link" : '/.*' > /dev/null; then + PRG="\$link" + else + PRG=`dirname "\$PRG"`"/\$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"\$PRG\"`/${appHomeRelativePath}" >/dev/null +APP_HOME="`pwd -P`" +cd "\$SAVED" >/dev/null + +APP_NAME="${applicationName}" +APP_BASE_NAME=`basename "\$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. +DEFAULT_JVM_OPTS=${defaultJvmOpts} + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "\$*" +} + +die () { + echo + echo "\$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$classpath +<% if ( mainClassName.startsWith('--module ') ) { %>MODULE_PATH=$modulePath<% } %> + +# Determine the Java command to use to start the JVM. +if [ -n "\$JAVA_HOME" ] ; then + if [ -x "\$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="\$JAVA_HOME/jre/sh/java" + else + JAVACMD="\$JAVA_HOME/bin/java" + fi + if [ ! -x "\$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: \$JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "\$cygwin" = "false" -a "\$darwin" = "false" -a "\$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ \$? -eq 0 ] ; then + if [ "\$MAX_FD" = "maximum" -o "\$MAX_FD" = "max" ] ; then + MAX_FD="\$MAX_FD_LIMIT" + fi + ulimit -n \$MAX_FD + if [ \$? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: \$MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: \$MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if \$darwin; then + GRADLE_OPTS="\$GRADLE_OPTS \\"-Xdock:name=\$APP_NAME\\" \\"-Xdock:icon=\$APP_HOME/media/gradle.icns\\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "\$cygwin" = "true" -o "\$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "\$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "\$CLASSPATH"` +<% if ( mainClassName.startsWith('--module ') ) { %> MODULE_PATH=`cygpath --path --mixed "\$MODULE_PATH"`<% } %> + JAVACMD=`cygpath --unix "\$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in \$ROOTDIRSRAW ; do + ROOTDIRS="\$ROOTDIRS\$SEP\$dir" + SEP="|" + done + OURCYGPATTERN="(^(\$ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "\$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="\$OURCYGPATTERN|(\$GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "\$@" ; do + CHECK=`echo "\$arg"|egrep -c "\$OURCYGPATTERN" -` + CHECK2=`echo "\$arg"|egrep -c "^-"` ### Determine if an option + + if [ \$CHECK -ne 0 ] && [ \$CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args\$i`=`cygpath --path --ignore --mixed "\$arg"` + else + eval `echo args\$i`="\"\$arg\"" + fi + i=`expr \$i + 1` + done + case \$i in + 0) set -- ;; + 1) set -- "\$args0" ;; + 2) set -- "\$args0" "\$args1" ;; + 3) set -- "\$args0" "\$args1" "\$args2" ;; + 4) set -- "\$args0" "\$args1" "\$args2" "\$args3" ;; + 5) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" ;; + 6) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" ;; + 7) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" ;; + 8) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" ;; + 9) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" "\$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\\\n "\$i" | sed "s/'/'\\\\\\\\''/g;1s/^/'/;\\\$s/\\\$/' \\\\\\\\/" ; done + echo " " +} +APP_ARGS=`save "\$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\"\$CLASSPATH\"" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "\"\$MODULE_PATH\"" <% } %>${mainClassName} "\$APP_ARGS" + +exec "\$JAVACMD" "\$@" diff --git a/facades/PC/src/main/startScripts/windowsStartScript.txt b/facades/PC/src/main/startScripts/windowsStartScript.txt new file mode 100644 index 00000000000..747fe6b0e6d --- /dev/null +++ b/facades/PC/src/main/startScripts/windowsStartScript.txt @@ -0,0 +1,90 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem ${applicationName} startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=.\ + +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME%${appHomeRelativePath} + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. +set DEFAULT_JVM_OPTS=${defaultJvmOpts} + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=$classpath +<% if ( mainClassName.startsWith('--module ') ) { %>set MODULE_PATH=$modulePath<% } %> + +@rem Execute ${applicationName} +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>"-D${appNameSystemProperty}=%APP_BASE_NAME%"<% } %> -classpath "%CLASSPATH%" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "%MODULE_PATH%" <% } %>${mainClassName} %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable ${exitEnvironmentVar} if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%${exitEnvironmentVar}%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 78a4846b23247110e26442effe7c2527222c6923 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:22:51 -0800 Subject: [PATCH 135/259] chore (build): rename scripts so the syntax highlighting is kinda right Issue for proper support of this template format is https://youtrack.jetbrains.com/issue/IDEABKL-6135 --- .../{unixStartScript.txt => unixStartScript.gsp} | 5 ++++- .../{windowsStartScript.txt => windowsStartScript.bat.gsp} | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) rename facades/PC/src/main/startScripts/{unixStartScript.txt => unixStartScript.gsp} (97%) rename facades/PC/src/main/startScripts/{windowsStartScript.txt => windowsStartScript.bat.gsp} (95%) diff --git a/facades/PC/src/main/startScripts/unixStartScript.txt b/facades/PC/src/main/startScripts/unixStartScript.gsp similarity index 97% rename from facades/PC/src/main/startScripts/unixStartScript.txt rename to facades/PC/src/main/startScripts/unixStartScript.gsp index 505325e09f2..463d3e5625d 100644 --- a/facades/PC/src/main/startScripts/unixStartScript.txt +++ b/facades/PC/src/main/startScripts/unixStartScript.gsp @@ -18,7 +18,10 @@ ############################################################################## ## -## ${applicationName} start up script for UN*X +## %{-- Copyright 2021 The Terasology Foundation --}% +%{-- SPDX-License-Identifier: Apache-2.0 --}% + +${applicationName} start up script for UN*X ## ############################################################################## diff --git a/facades/PC/src/main/startScripts/windowsStartScript.txt b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp similarity index 95% rename from facades/PC/src/main/startScripts/windowsStartScript.txt rename to facades/PC/src/main/startScripts/windowsStartScript.bat.gsp index 747fe6b0e6d..afd5d4ad06e 100644 --- a/facades/PC/src/main/startScripts/windowsStartScript.txt +++ b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp @@ -17,7 +17,10 @@ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem -@rem ${applicationName} startup script for Windows +@rem %{-- Copyright 2021 The Terasology Foundation --}% +%{-- SPDX-License-Identifier: Apache-2.0 --}% + +${applicationName} startup script for Windows @rem @rem ########################################################################## From 01ae5db1f26f48cf0ee614c982d3d99611406f68 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:27:31 -0800 Subject: [PATCH 136/259] fix (build): don't set CLASSPATH in script, use the jar with the classpath in its manifest [Windows] otherwise cmd.exe fails with "the line is too long" errors. https://github.com/gradle/gradle/issues/1989 --- facades/PC/src/main/startScripts/windowsStartScript.bat.gsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp index afd5d4ad06e..6ee6b59b1fe 100644 --- a/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp +++ b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp @@ -13,6 +13,7 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem https://github.com/gradle/gradle/blob/124712713a77a6813e112ae1b68f248deca6a816/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/windowsStartScript.txt @if "%DEBUG%" == "" @echo off @rem ########################################################################## @@ -71,11 +72,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=$classpath <% if ( mainClassName.startsWith('--module ') ) { %>set MODULE_PATH=$modulePath<% } %> @rem Execute ${applicationName} -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>"-D${appNameSystemProperty}=%APP_BASE_NAME%"<% } %> -classpath "%CLASSPATH%" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "%MODULE_PATH%" <% } %>${mainClassName} %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>"-D${appNameSystemProperty}=%APP_BASE_NAME%"<% } %> <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "%MODULE_PATH%" <% } %>-jar lib\\Terasology.jar %* :end @rem End local scope for the variables with windows NT shell From 957cd1891f9c6f0babd7b218625f50a05ea61680 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:46:46 -0800 Subject: [PATCH 137/259] fix (build): clean up after wayword auto-copyright-header-insertion --- .idea/copyright/profiles_settings.xml | 3 +++ .../src/main/startScripts/unixStartScript.gsp | 24 +++++-------------- .../startScripts/windowsStartScript.bat.gsp | 24 +++++-------------- 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index 133be3edacd..8f72e4b44d2 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,5 +1,8 @@ + + diff --git a/facades/PC/src/main/startScripts/unixStartScript.gsp b/facades/PC/src/main/startScripts/unixStartScript.gsp index 463d3e5625d..c45b0970d20 100644 --- a/facades/PC/src/main/startScripts/unixStartScript.gsp +++ b/facades/PC/src/main/startScripts/unixStartScript.gsp @@ -1,27 +1,15 @@ #!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# Copyright 2021 The Terasology Foundation, 2015 the original author or authors. +# SPDX-License-Identifier: Apache-2.0 # -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Derived from +# https://github.com/gradle/gradle/blob/f38a522/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/windowsStartScript.txt # +# Alternatively use our Launcher from: https://github.com/MovingBlocks/TerasologyLauncher/releases ############################################################################## ## -## %{-- Copyright 2021 The Terasology Foundation --}% -%{-- SPDX-License-Identifier: Apache-2.0 --}% - -${applicationName} start up script for UN*X +## ${applicationName} start up script for UN*X ## ############################################################################## diff --git a/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp index 6ee6b59b1fe..a4cf2790ac4 100644 --- a/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp +++ b/facades/PC/src/main/startScripts/windowsStartScript.bat.gsp @@ -1,27 +1,15 @@ +@rem Copyright 2021 The Terasology Foundation, 2015 the original author or authors. +@rem SPDX-License-Identifier: Apache-2.0 @rem -@rem Copyright 2015 the original author or authors. +@rem Derived from +@rem https://github.com/gradle/gradle/blob/f38a522/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/windowsStartScript.txt @rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem https://github.com/gradle/gradle/blob/124712713a77a6813e112ae1b68f248deca6a816/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/windowsStartScript.txt +@rem Alternatively use our Launcher from: https://github.com/MovingBlocks/TerasologyLauncher/releases @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem -@rem %{-- Copyright 2021 The Terasology Foundation --}% -%{-- SPDX-License-Identifier: Apache-2.0 --}% - -${applicationName} startup script for Windows +@rem ${applicationName} startup script for Windows @rem @rem ########################################################################## From 5248ea5a945a4aad9c2cf0f5b484dde90159d161 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:49:42 -0800 Subject: [PATCH 138/259] fix (build): don't set CLASSPATH in script, use the jar with the classpath in its manifest [Unix] Unix shells have a longer line length limit than cmd.exe, but using the jar manifest will be more consistent with Windows and Launcher. --- facades/PC/src/main/startScripts/unixStartScript.gsp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/facades/PC/src/main/startScripts/unixStartScript.gsp b/facades/PC/src/main/startScripts/unixStartScript.gsp index c45b0970d20..cdfa1be4684 100644 --- a/facades/PC/src/main/startScripts/unixStartScript.gsp +++ b/facades/PC/src/main/startScripts/unixStartScript.gsp @@ -71,7 +71,6 @@ case "`uname`" in ;; esac -CLASSPATH=$classpath <% if ( mainClassName.startsWith('--module ') ) { %>MODULE_PATH=$modulePath<% } %> # Determine the Java command to use to start the JVM. @@ -171,6 +170,6 @@ save () { APP_ARGS=`save "\$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\"\$CLASSPATH\"" <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "\"\$MODULE_PATH\"" <% } %>${mainClassName} "\$APP_ARGS" +eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %> <% if ( mainClassName.startsWith('--module ') ) { %>--module-path "\"\$MODULE_PATH\"" <% } %>-jar lib/Terasology.jar "\$APP_ARGS" exec "\$JAVACMD" "\$@" From 5bb9dd4a2d640fb275b833328813c980b2089100 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 12:57:02 -0800 Subject: [PATCH 139/259] fix (build): use the jar-classpath start scripts --- facades/PC/build.gradle.kts | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index a3dba27512d..e0beb8383bc 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -68,6 +68,7 @@ val displayVersion = versionBase application { applicationName = "Terasology" + executableDir = "/" mainClass.set(extra.get("mainClassName") as String) } @@ -209,7 +210,9 @@ tasks.named("jar") { manifest { //TODO: Maybe later add the engine's version number into here? attributes["Main-Class"] = mainClassName - attributes["Class-Path"] = configurations["runtimeClasspath"].map { it.name }.joinToString(" ") + // A classpath in the manifest avoids the problem of having to put a classpath on the command line and + // "line is too long" errors: https://github.com/gradle/gradle/issues/1989 + attributes["Class-Path"] = configurations["runtimeClasspath"].joinToString(" ") { it.name } attributes["Implementation-Title"] = "Terasology-" + project.name attributes["Implementation-Version"] = """${env["BUILD_NUMBER"]}, ${env["GIT_BRANCH"]}, ${env["BUILD_ID"]}""" } @@ -260,12 +263,12 @@ tasks.register("distForLauncher") { val tail = pathSegments.sliceArray(1 until pathSegments.size) relativePath = RelativePath(true, launcherLibraryDirectory, *tail) } + } - application.executableDir -> { - // I don't know how the "lib/" makes its way in to the classpath used by CreateStartScripts, - // so we're adjusting it after-the-fact. - filter(ScriptClasspathRewriter(this, defaultLibraryDirectory, launcherLibraryDirectory)) - } + if (this.sourcePath == "Terasology" || this.sourcePath == "Terasology.bat") { + // I don't know how the "lib/" makes its way in to the classpath used by CreateStartScripts, + // so we're adjusting it after-the-fact. + filter(ScriptClasspathRewriter(this, defaultLibraryDirectory, launcherLibraryDirectory)) } } }) @@ -273,16 +276,23 @@ tasks.register("distForLauncher") { class ScriptClasspathRewriter(file: FileCopyDetails, val oldDirectory: String, val newDirectory: String) : Transformer { private val isBatchFile = file.name.endsWith(".bat") - private val assignment = if (isBatchFile) "set CLASSPATH=" else "CLASSPATH=" - override fun transform(line: String): String = if (line.startsWith(assignment)) { - if (isBatchFile) { - line.replace("\\$oldDirectory\\", "\\$newDirectory\\") + override fun transform(line: String): String = if (isBatchFile) { + line.replace("$oldDirectory\\", "$newDirectory\\") } else { - line.replace("/$oldDirectory/", "/$newDirectory/") + line.replace("$oldDirectory/", "$newDirectory/") } - } else { - line +} + +tasks.named("startScripts") { + // Use start scripts that invoke java with `-jar` with the classpath in the jar manifest, + // instead of including classpath on the command line. Avoids "line is too long" errors. + // See https://github.com/gradle/gradle/issues/1989 + (unixStartScriptGenerator as TemplateBasedScriptGenerator).apply { + template = resources.text.fromFile("src/main/startScripts/unixStartScript.gsp") + } + (windowsStartScriptGenerator as TemplateBasedScriptGenerator).apply { + template = resources.text.fromFile("src/main/startScripts/windowsStartScript.bat.gsp") } } From 1afeec9df306df29bf17d0cf7ad0ccb0bda297a6 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 19 Jan 2021 13:12:23 -0800 Subject: [PATCH 140/259] chore (build): correct reference to upstream --- facades/PC/src/main/startScripts/unixStartScript.gsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facades/PC/src/main/startScripts/unixStartScript.gsp b/facades/PC/src/main/startScripts/unixStartScript.gsp index cdfa1be4684..ee7249d5fd3 100644 --- a/facades/PC/src/main/startScripts/unixStartScript.gsp +++ b/facades/PC/src/main/startScripts/unixStartScript.gsp @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # # Derived from -# https://github.com/gradle/gradle/blob/f38a522/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/windowsStartScript.txt +# https://github.com/gradle/gradle/blob/f38a522/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # # Alternatively use our Launcher from: https://github.com/MovingBlocks/TerasologyLauncher/releases From 308f05ec00e6980fb9fdabc212423b68d8037792 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 21 Jan 2021 12:48:22 -0800 Subject: [PATCH 141/259] feat(JOML): migrate Mesh AABBf (#4415) Co-authored-by: Tobias Nett --- .../internal/StorageManagerTest.java | 4 +- .../java/org/terasology/world/ChunkTest.java | 6 ++- .../headless/assets/HeadlessMesh.java | 9 +++-- .../logic/players/LocalPlayerSystem.java | 17 ++++---- .../internal/AbstractStorageManager.java | 7 +++- .../terasology/rendering/AABBRenderer.java | 40 ++++++++++--------- .../rendering/BlockOverlayRenderer.java | 4 +- .../rendering/assets/mesh/Mesh.java | 35 +++++++++++++++- .../terasology/rendering/cameras/Camera.java | 3 +- .../rendering/cameras/ViewFrustum.java | 37 ++++++++--------- .../rendering/logic/MeshRenderer.java | 2 +- .../nui/internal/LwjglCanvasRenderer.java | 7 ++-- .../rendering/opengl/OpenGLMesh.java | 9 +++-- .../world/chunks/RenderableChunk.java | 3 +- .../world/chunks/internal/ChunkImpl.java | 16 ++++---- 15 files changed, 124 insertions(+), 75 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java index 97e8e4a8699..721c14cbe4a 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java @@ -39,6 +39,7 @@ import org.terasology.entitySystem.entity.internal.EngineEntityManager; import org.terasology.entitySystem.stubs.EntityRefComponent; import org.terasology.entitySystem.stubs.StringComponent; +import org.terasology.joml.geom.AABBfc; import org.terasology.logic.location.LocationComponent; import org.terasology.math.JomlUtil; import org.terasology.module.ModuleEnvironment; @@ -339,7 +340,8 @@ public void testEntitySurvivesStorageInChunkStore() throws Exception { EntityRef entity = entityManager.create(); long id = entity.getId(); LocationComponent locationComponent = new LocationComponent(); - Vector3f positionInChunk = new Vector3f(JomlUtil.from(chunk.getAABB().getMin())); + AABBfc aabb = chunk.getAABB(); + Vector3f positionInChunk = new Vector3f(aabb.minX(), aabb.minY(), aabb.minZ()); positionInChunk.x += 1; positionInChunk.y += 1; positionInChunk.z += 1; diff --git a/engine-tests/src/test/java/org/terasology/world/ChunkTest.java b/engine-tests/src/test/java/org/terasology/world/ChunkTest.java index be2e63236d4..eb609754765 100644 --- a/engine-tests/src/test/java/org/terasology/world/ChunkTest.java +++ b/engine-tests/src/test/java/org/terasology/world/ChunkTest.java @@ -20,6 +20,7 @@ import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; +import org.terasology.joml.geom.AABBfc; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; @@ -73,8 +74,9 @@ public void testChangeBlock() { @Test public void testGetAabb() { - assertEquals(new Vector3f(0, 0, 0), chunk.getAABB().getMin()); - assertEquals(new Vector3f(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z), chunk.getAABB().getMax()); + AABBfc aabb = chunk.getAABB(); + assertEquals(new Vector3f(0, 0, 0), new Vector3f(aabb.minX(), aabb.minY(), aabb.minZ())); + assertEquals(new Vector3f(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z), new Vector3f(aabb.maxX(), aabb.maxY(), aabb.maxZ())); } } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMesh.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMesh.java index 991f2e5c975..9a18a42ca38 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMesh.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMesh.java @@ -18,14 +18,15 @@ import gnu.trove.list.TFloatList; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.rendering.assets.mesh.Mesh; import org.terasology.rendering.assets.mesh.MeshData; public class HeadlessMesh extends Mesh { protected MeshData data; - protected AABB aabb; + protected AABBf aabb = new AABBf(); public HeadlessMesh(ResourceUrn urn, AssetType assetType, MeshData meshData) { super(urn, assetType); @@ -35,11 +36,11 @@ public HeadlessMesh(ResourceUrn urn, AssetType assetType, MeshData @Override protected void doReload(MeshData meshData) { this.data = meshData; - this.aabb = AABB.createEncompasing(meshData.getVertices()); + getBound(meshData, aabb); } @Override - public AABB getAABB() { + public AABBfc getAABB() { return aabb; } diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java index e81c7ff4a15..d4674b918a1 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java @@ -16,6 +16,7 @@ package org.terasology.logic.players; import org.joml.Math; +import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; import org.terasology.assets.ResourceUrn; @@ -50,6 +51,8 @@ import org.terasology.input.binds.movement.VerticalRealMovementAxis; import org.terasology.input.events.MouseAxisEvent; import org.terasology.input.events.MouseAxisEvent.MouseAxis; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.logic.characters.CharacterComponent; import org.terasology.logic.characters.CharacterHeldItemComponent; import org.terasology.logic.characters.CharacterMoveInputEvent; @@ -128,11 +131,11 @@ public class LocalPlayerSystem extends BaseComponentSystem implements UpdateSubs @In private Time time; - private BlockOverlayRenderer aabbRenderer = new AABBRenderer(AABB.createEmpty()); + private BlockOverlayRenderer aabbRenderer = new AABBRenderer(new AABBf()); private int inputSequenceNumber = 1; - private AABB aabb; + private AABBf aabb = new AABBf(); public void setPlayerCamera(Camera camera) { playerCamera = camera; @@ -371,23 +374,21 @@ public void onTargetChanged(PlayerTargetChangedEvent event, EntityRef entity) { EntityRef target = event.getNewTarget(); if (target.exists()) { LocationComponent location = target.getComponent(LocationComponent.class); - if (location != null && !Float.isNaN(location.getWorldPosition().x)) { + if (location != null) { BlockComponent blockComp = target.getComponent(BlockComponent.class); BlockRegionComponent blockRegion = target.getComponent(BlockRegionComponent.class); if (blockComp != null || blockRegion != null) { Vector3f blockPos = location.getWorldPosition(new Vector3f()); Block block = worldProvider.getBlock(blockPos); - aabb = JomlUtil.from(block.getBounds(blockPos)); + aabb.set(block.getBounds(blockPos)); } else { MeshComponent mesh = target.getComponent(MeshComponent.class); if (mesh != null && mesh.mesh != null) { - aabb = mesh.mesh.getAABB(); - aabb = aabb.transform(location.getWorldRotation(), location.getWorldPosition(), location.getWorldScale()); + aabb.set(mesh.mesh.getAABB()); + aabb.transform(new Matrix4f().translationRotateScale(location.getWorldPosition(new Vector3f()), location.getWorldRotation(new Quaternionf()), location.getWorldScale())); } } } - } else { - aabb = null; } } diff --git a/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java b/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java index c3fc68fd316..840282c6ee6 100644 --- a/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java +++ b/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java @@ -17,11 +17,14 @@ package org.terasology.persistence.internal; import com.google.common.collect.Lists; +import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.internal.EngineEntityManager; import org.terasology.entitySystem.entity.internal.OwnershipHelper; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.logic.location.LocationComponent; import org.terasology.math.AABB; import org.terasology.math.JomlUtil; @@ -184,12 +187,12 @@ protected EntityData.PlayerStore loadPlayerStoreData(String playerId) { protected Collection getEntitiesOfChunk(Chunk chunk) { List entitiesToStore = Lists.newArrayList(); - AABB aabb = chunk.getAABB(); + AABBfc aabb = chunk.getAABB(); for (EntityRef entity : getEntityManager().getEntitiesWith(LocationComponent.class)) { if (!entity.getOwner().exists() && !entity.isAlwaysRelevant() && !entity.hasComponent(ClientComponent.class)) { LocationComponent loc = entity.getComponent(LocationComponent.class); if (loc != null&& !Float.isNaN(loc.getWorldPosition().x)) { - if (aabb.contains(loc.getWorldPosition())) { + if (aabb.containsPoint(loc.getWorldPosition(new Vector3f()))) { entitiesToStore.add(entity); } } diff --git a/engine/src/main/java/org/terasology/rendering/AABBRenderer.java b/engine/src/main/java/org/terasology/rendering/AABBRenderer.java index 88db5e98085..94207edf319 100644 --- a/engine/src/main/java/org/terasology/rendering/AABBRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/AABBRenderer.java @@ -16,11 +16,12 @@ package org.terasology.rendering; +import org.joml.Vector3f; +import org.joml.Vector4f; import org.lwjgl.opengl.GL11; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.AABB; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector4f; import org.terasology.module.sandbox.API; import org.terasology.registry.CoreRegistry; @@ -52,16 +53,16 @@ public class AABBRenderer implements BlockOverlayRenderer { private int displayListSolid = -1; private Vector4f solidColor = new Vector4f(1f, 1f, 1f, 1f); - private AABB aabb; + private AABBf aabb = new AABBf(); - public AABBRenderer(AABB aabb) { - this.aabb = aabb; + public AABBRenderer(AABBfc aabb) { + this.aabb.set(aabb); } @Override - public void setAABB(AABB from) { + public void setAABB(AABBfc from) { if (from != null && !from.equals(this.aabb)) { - this.aabb = from; + this.aabb.set(from); dispose(); } } @@ -90,8 +91,9 @@ public void render() { CoreRegistry.get(ShaderManager.class).enableDefault(); glPushMatrix(); - Vector3f cameraPosition = CoreRegistry.get(LocalPlayer.class).getViewPosition(); - glTranslated(aabb.getCenter().x - cameraPosition.x, -cameraPosition.y, aabb.getCenter().z - cameraPosition.z); + Vector3f cameraPosition = CoreRegistry.get(LocalPlayer.class).getViewPosition(new Vector3f()); + Vector3f center = aabb.center(new Vector3f()); + glTranslated(center.x - cameraPosition.x, -cameraPosition.y, center.z - cameraPosition.z); renderLocally(); @@ -102,8 +104,9 @@ public void renderSolid() { CoreRegistry.get(ShaderManager.class).enableDefault(); glPushMatrix(); - Vector3f cameraPosition = CoreRegistry.get(LocalPlayer.class).getViewPosition(); - glTranslated(aabb.getCenter().x - cameraPosition.x, -cameraPosition.y, aabb.getCenter().z - cameraPosition.z); + Vector3f cameraPosition = CoreRegistry.get(LocalPlayer.class).getViewPosition(new Vector3f()); + Vector3f center = aabb.center(new Vector3f()); + glTranslated(center.x - cameraPosition.x, -cameraPosition.y, center.z - cameraPosition.z); renderSolidLocally(); @@ -123,9 +126,9 @@ public void renderLocally() { if (displayListWire == -1) { generateDisplayListWire(); } - + Vector3f center = aabb.center(new Vector3f()); glPushMatrix(); - glTranslated(0f, aabb.getCenter().y, 0f); + glTranslated(0f, center.y, 0f); glCallList(displayListWire); @@ -141,7 +144,8 @@ public void renderSolidLocally() { glEnable(GL_BLEND); glPushMatrix(); - glTranslated(0f, aabb.getCenter().y, 0f); + Vector3f center = aabb.center(new Vector3f()); + glTranslated(0f, center.y, 0f); glScalef(1.5f, 1.5f, 1.5f); glCallList(displayListSolid); @@ -157,7 +161,7 @@ private void generateDisplayListSolid() { glBegin(GL_QUADS); glColor4f(solidColor.x, solidColor.y, solidColor.z, solidColor.w); - Vector3f dimensions = aabb.getExtents(); + Vector3f dimensions = aabb.extent(new Vector3f()); GL11.glVertex3f(-dimensions.x, dimensions.y, dimensions.z); GL11.glVertex3f(dimensions.x, dimensions.y, dimensions.z); @@ -201,7 +205,7 @@ private void generateDisplayListWire() { glNewList(displayListWire, GL11.GL_COMPILE); glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - Vector3f dimensions = aabb.getExtents(); + Vector3f dimensions = aabb.extent(new Vector3f()); // FRONT glBegin(GL_LINE_LOOP); @@ -253,7 +257,7 @@ private void generateDisplayListWire() { glEndList(); } - public AABB getAABB() { + public AABBfc getAABB() { return aabb; } } diff --git a/engine/src/main/java/org/terasology/rendering/BlockOverlayRenderer.java b/engine/src/main/java/org/terasology/rendering/BlockOverlayRenderer.java index 0e006a50b21..e2f4646f5a8 100644 --- a/engine/src/main/java/org/terasology/rendering/BlockOverlayRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/BlockOverlayRenderer.java @@ -16,12 +16,12 @@ package org.terasology.rendering; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBfc; /** */ public interface BlockOverlayRenderer { - void setAABB(AABB aabb); + void setAABB(AABBfc aabb); /** * Maintained for API compatibility diff --git a/engine/src/main/java/org/terasology/rendering/assets/mesh/Mesh.java b/engine/src/main/java/org/terasology/rendering/assets/mesh/Mesh.java index 32d311dbe55..ea74f75026f 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/mesh/Mesh.java +++ b/engine/src/main/java/org/terasology/rendering/assets/mesh/Mesh.java @@ -19,7 +19,8 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; public abstract class Mesh extends Asset { @@ -33,7 +34,37 @@ protected Mesh(ResourceUrn urn, AssetType assetType) { super(urn, assetType); } - public abstract AABB getAABB(); + public abstract AABBfc getAABB(); + + protected AABBf getBound(MeshData data, AABBf dest) { + TFloatList vertices = data.getVertices(); + int vertexCount = vertices.size() / 3; + if (vertexCount == 0) { + dest.set(Float.POSITIVE_INFINITY, + Float.POSITIVE_INFINITY, + Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY, + Float.NEGATIVE_INFINITY, + Float.NEGATIVE_INFINITY); + } + + dest.minX = vertices.get(0); + dest.minY = vertices.get(1); + dest.minZ = vertices.get(2); + dest.maxX = vertices.get(0); + dest.maxY = vertices.get(1); + dest.maxZ = vertices.get(2); + + for (int index = 1; index < vertexCount; ++index) { + dest.minX = Math.min(dest.minX, vertices.get(3 * index)); + dest.minY = Math.max(dest.minY, vertices.get(3 * index)); + dest.minZ = Math.min(dest.minZ, vertices.get(3 * index + 1)); + dest.maxX = Math.max(dest.maxX, vertices.get(3 * index + 1)); + dest.maxY = Math.min(dest.maxY, vertices.get(3 * index + 2)); + dest.maxZ = Math.max(dest.maxZ, vertices.get(3 * index + 2)); + } + return dest; + } public abstract TFloatList getVertices(); diff --git a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java index 6afaf5553d4..6efae2c3427 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java @@ -11,6 +11,7 @@ import org.joml.Vector3fc; import org.lwjgl.BufferUtils; import org.terasology.config.Config; +import org.terasology.joml.geom.AABBfc; import org.terasology.math.AABB; import org.terasology.math.Direction; import org.terasology.math.JomlUtil; @@ -259,7 +260,7 @@ public boolean hasInSight(AABB aabb) { return viewFrustum.intersects(aabb); } - public boolean hasInSight(AABBf aabb) { + public boolean hasInSight(AABBfc aabb) { return viewFrustum.intersects(aabb); } } diff --git a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java index ecaedeb5ead..0aea2f73f0c 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java @@ -18,6 +18,7 @@ import org.terasology.joml.geom.AABBf; import org.joml.Vector3fc; import org.lwjgl.BufferUtils; +import org.terasology.joml.geom.AABBfc; import org.terasology.logic.players.LocalPlayer; import org.terasology.math.AABB; import org.terasology.math.JomlUtil; @@ -147,7 +148,7 @@ public boolean intersects(double x, double y, double z) { * Returns true if this view frustum intersects the given AABB. * * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #intersects(AABBf)}. + * {@link #intersects(AABBfc)}. */ public boolean intersects(AABB aabb) { return intersects(JomlUtil.from(aabb)); @@ -156,40 +157,40 @@ public boolean intersects(AABB aabb) { /** * Returns true if this view frustum intersects the given AABB. */ - public boolean intersects(AABBf aabb) { + public boolean intersects(AABBfc aabb) { Vector3f cp = CoreRegistry.get(LocalPlayer.class).getViewPosition(); for (int i = 0; i < 6; i++) { - if (planes[i].getA() * (aabb.minX - cp.x) + planes[i].getB() * (aabb.minY - cp.y) - + planes[i].getC() * (aabb.maxZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.minX() - cp.x) + planes[i].getB() * (aabb.minY() - cp.y) + + planes[i].getC() * (aabb.maxZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.maxX - cp.x) + planes[i].getB() * (aabb.minY - cp.y) - + planes[i].getC() * (aabb.maxZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.maxX() - cp.x) + planes[i].getB() * (aabb.minY() - cp.y) + + planes[i].getC() * (aabb.maxZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.maxX - cp.x) + planes[i].getB() * (aabb.maxY - cp.y) - + planes[i].getC() * (aabb.maxZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.maxX() - cp.x) + planes[i].getB() * (aabb.maxY() - cp.y) + + planes[i].getC() * (aabb.maxZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.minX - cp.x) + planes[i].getB() * (aabb.maxY - cp.y) - + planes[i].getC() * (aabb.maxZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.minX() - cp.x) + planes[i].getB() * (aabb.maxY() - cp.y) + + planes[i].getC() * (aabb.maxZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.minX - cp.x) + planes[i].getB() * (aabb.minY - cp.y) - + planes[i].getC() * (aabb.minZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.minX() - cp.x) + planes[i].getB() * (aabb.minY() - cp.y) + + planes[i].getC() * (aabb.minZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.maxX - cp.x) + planes[i].getB() * (aabb.minY - cp.y) - + planes[i].getC() * (aabb.minZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.maxX() - cp.x) + planes[i].getB() * (aabb.minY() - cp.y) + + planes[i].getC() * (aabb.minZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.maxX - cp.x) + planes[i].getB() * (aabb.maxY - cp.y) - + planes[i].getC() * (aabb.minZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.maxX() - cp.x) + planes[i].getB() * (aabb.maxY() - cp.y) + + planes[i].getC() * (aabb.minZ() - cp.z) + planes[i].getD() > 0) { continue; } - if (planes[i].getA() * (aabb.minX - cp.x) + planes[i].getB() * (aabb.maxY - cp.y) - + planes[i].getC() * (aabb.minZ - cp.z) + planes[i].getD() > 0) { + if (planes[i].getA() * (aabb.minX() - cp.x) + planes[i].getB() * (aabb.maxY() - cp.y) + + planes[i].getC() * (aabb.minZ() - cp.z) + planes[i].getD() > 0) { continue; } return false; diff --git a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java index a2f1db4cc3c..084758b8819 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/MeshRenderer.java @@ -214,7 +214,7 @@ private void renderEntitiesByMaterial(SetMultimap meshByMat matrixCameraSpace.translationRotateScale(offsetFromCamera, worldRot, worldScale); - AABBf aabb = JomlUtil.from(meshComp.mesh.getAABB()).transform(new Matrix4f().translationRotateScale(worldPos, worldRot, worldScale)); + AABBf aabb = meshComp.mesh.getAABB().transform(new Matrix4f().translationRotateScale(worldPos, worldRot, worldScale), new AABBf()); if (worldRenderer.getActiveCamera().hasInSight(aabb)) { if (meshComp.mesh != lastMesh) { if (lastMesh != null) { diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java index 393efbd77fc..86e686941a4 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java @@ -8,6 +8,7 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Quaternionfc; +import org.terasology.joml.geom.AABBfc; import org.terasology.joml.geom.Rectanglef; import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2f; @@ -181,10 +182,10 @@ public void drawMesh(Mesh mesh, Material material, Rectanglei drawRegion, Rectan return; } - AABB meshAABB = mesh.getAABB(); - Vector3f meshExtents = JomlUtil.from(meshAABB.getExtents()); + AABBfc meshAABB = mesh.getAABB(); + Vector3f meshExtents = meshAABB.extent(new Vector3f()); float fitScale = 0.35f * Math.min(drawRegion.lengthX(), drawRegion.lengthY()) / Math.max(meshExtents.x, Math.max(meshExtents.y, meshExtents.z)); - Vector3f centerOffset = JomlUtil.from(meshAABB.getCenter()); + Vector3f centerOffset = meshAABB.center(new Vector3f()); centerOffset.mul(-1.0f); Matrix4f centerTransform = new Matrix4f().translationRotateScale(centerOffset,new Quaternionf(),1); diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java index 352bb9ad253..ae0d239eb88 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java @@ -32,6 +32,8 @@ import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.math.AABB; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.mesh.Mesh; @@ -59,7 +61,7 @@ public class OpenGLMesh extends Mesh { private static final Logger logger = LoggerFactory.getLogger(OpenGLMesh.class); private static final int FLOAT_SIZE = 4; - private AABB aabb; + private AABBf aabb = new AABBf(); private MeshData data; @@ -96,7 +98,7 @@ protected void doReload(MeshData newData) { } @Override - public AABB getAABB() { + public AABBfc getAABB() { return aabb; } @@ -226,8 +228,7 @@ private void buildMesh(MeshData newData) { createVertexBuffer(parts, partSizes, vertexCount, vertexSize); createIndexBuffer(newData.getIndices()); - - aabb = AABB.createEncompasing(newData.getVertices()); + getBound(newData, aabb); } private void createVertexBuffer(List parts, TIntList partSizes, int vertexCount, int vertexSize) { diff --git a/engine/src/main/java/org/terasology/world/chunks/RenderableChunk.java b/engine/src/main/java/org/terasology/world/chunks/RenderableChunk.java index c73a9ed8ff1..55717827c36 100644 --- a/engine/src/main/java/org/terasology/world/chunks/RenderableChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/RenderableChunk.java @@ -15,6 +15,7 @@ */ package org.terasology.world.chunks; +import org.terasology.joml.geom.AABBfc; import org.terasology.math.AABB; import org.terasology.module.sandbox.API; import org.terasology.rendering.primitives.ChunkMesh; @@ -28,7 +29,7 @@ public interface RenderableChunk extends LitChunk { void setDirty(boolean dirty); - AABB getAABB(); + AABBfc getAABB(); void setMesh(ChunkMesh newMesh); diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java index 65527e84e3f..48523d174d0 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java @@ -20,6 +20,8 @@ import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; import org.terasology.math.AABB; import org.terasology.math.JomlUtil; import org.terasology.math.geom.BaseVector3i; @@ -71,7 +73,7 @@ public class ChunkImpl implements Chunk { private TeraArray[] extraData; private volatile TeraArray[] extraDataSnapshots; - private AABB aabb; + private AABBf aabb = new AABBf(); private BlockRegion region; private boolean disposed; @@ -341,14 +343,12 @@ public int chunkToWorldPositionZ(int z) { } @Override - public AABB getAABB() { - if (aabb == null) { - Vector3f min = getChunkWorldOffset().toVector3f(); - Vector3f max = ChunkConstants.CHUNK_SIZE.toVector3f(); - max.add(min); - aabb = AABB.createMinMax(min, max); + public AABBfc getAABB() { + if (!aabb.isValid()) { + org.joml.Vector3f min = JomlUtil.from(getChunkWorldOffset().toVector3f()); + org.joml.Vector3f max = new org.joml.Vector3f(Chunks.CHUNK_SIZE).add(min); + aabb = new AABBf(min, max); } - return aabb; } From 934b9436e67235ac18e43c1e0bd440f78450ad91 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Sat, 23 Jan 2021 03:12:01 +0000 Subject: [PATCH 142/259] Fix the upper half of each chunk behaving strangely. (#4418) --- .../org/terasology/world/internal/WorldProviderCoreImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index f7d160d0f20..31b17fd96c6 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -275,7 +275,7 @@ private void notifyExtraDataChanged(int index, Vector3ic pos, int newData, int o public Block getBlock(int x, int y, int z) { CoreChunk chunk = chunkProvider.getChunk(Chunks.toChunkPos(x, y, z, new Vector3i())); if (chunk != null) { - return chunk.getBlock(Chunks.toRelativeX(x), Chunks.toRelativeX(y), Chunks.toRelativeX(z)); + return chunk.getBlock(Chunks.toRelativeX(x), Chunks.toRelativeY(y), Chunks.toRelativeZ(z)); } return unloadedBlock; } From 045a924fc576e3ccc0ba613bf292488ae613e274 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 23 Jan 2021 03:12:44 -0800 Subject: [PATCH 143/259] feat(JOML): migrate BlockSelectionRenderer (#4411) --- .../selection/BlockSelectionRenderer.java | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java index 9059fdedd84..39a508e46a2 100644 --- a/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/world/selection/BlockSelectionRenderer.java @@ -20,7 +20,6 @@ import org.terasology.math.JomlUtil; import org.terasology.math.geom.Rect2f; import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.assets.material.Material; @@ -110,27 +109,6 @@ public void endRenderOverlay() { defaultTextured.deactivateFeature(ShaderProgramFeature.FEATURE_ALPHA_REJECT); } - /** - * - * @param blockPos - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #renderMark(Vector3ic)}. - */ - @Deprecated - public void renderMark(Vector3i blockPos) { - Vector3f cameraPos = getCameraPosition(); - - glPushMatrix(); - glTranslated(blockPos.x - cameraPos.x, blockPos.y - cameraPos.y, blockPos.z - cameraPos.z); - - glMatrixMode(GL_MODELVIEW); - - overlayMesh.render(); - - glPopMatrix(); - } - - public void renderMark(Vector3ic blockPos) { Vector3f cameraPos = getCameraPosition(); @@ -144,11 +122,11 @@ public void renderMark(Vector3ic blockPos) { glPopMatrix(); } - public void renderMark2(Vector3i blockPos) { + public void renderMark2(Vector3ic blockPos) { Vector3f cameraPos = getCameraPosition(); glPushMatrix(); - glTranslated(blockPos.x - cameraPos.x, blockPos.y - cameraPos.y, blockPos.z - cameraPos.z); + glTranslated(blockPos.x() - cameraPos.x, blockPos.y() - cameraPos.y, blockPos.z() - cameraPos.z); glMatrixMode(GL_MODELVIEW); From 2427ce3360d79d0cfca017f213264a50ff7a6bc9 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 23 Jan 2021 20:38:40 +0100 Subject: [PATCH 144/259] feat(world): add APIs to compute `Chunks` values in-place (#4420) --- .../org/terasology/world/chunks/Chunks.java | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/Chunks.java b/engine/src/main/java/org/terasology/world/chunks/Chunks.java index 1fa0453e4c5..a1f0ed6bf17 100644 --- a/engine/src/main/java/org/terasology/world/chunks/Chunks.java +++ b/engine/src/main/java/org/terasology/world/chunks/Chunks.java @@ -41,6 +41,8 @@ public final class Chunks { private Chunks() { } + //-- chunk position ----------------------------------------------------------------------------------------------// + /** * Returns the chunk coordinate given the position and the chunk power. * @@ -85,7 +87,6 @@ public static int toChunkPosZ(int z) { return toChunkPos(z, CHUNK_POWER.z()); } - /** * The position of the chunk given the coordinate and size of chunk in powers of 2. * @@ -125,11 +126,26 @@ public static Vector3i toChunkPos(int x, int y, int z, Vector3i dest) { * @param pos absolute coordinate of the block * @param dest will hold the result * @return dest + * + * @see #toChunkPos(Vector3i) */ public static Vector3i toChunkPos(Vector3ic pos, Vector3i dest) { return toChunkPos(pos.x(), pos.y(), pos.z(), POWER_X, POWER_Y, POWER_Z, dest); } + /** + * Compute (in-place) the position of the chunk given the world coordinate {@code pos}. + * + * This uses the default power ({@link #POWER_X}, {@link #POWER_Y}, {@link #POWER_Z}) + * + *

default chunk size ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z})

+ * + * @param pos absolute coordinate of the block + * @return the input vector {@code pos} modified to hold the result + */ + public static Vector3i toChunkPos(Vector3i pos) { + return toChunkPos(pos, pos); + } /** * The position of the chunk given the coordinate and size of chunk in powers of 2. @@ -170,7 +186,6 @@ public static Vector3i toChunkPos(float x, float y, float z, Vector3i dest) { Math.roundUsing(z, RoundingMode.FLOOR), POWER_X, POWER_Y, POWER_Z, dest); } - /** * The position of the chunk given the coordinate and size of chunk in powers of 2. * @@ -191,6 +206,9 @@ public static Vector3i toChunkPos(int x, int y, int z, int chunkX, int chunkY, i toChunkPos(y, chunkY), toChunkPos(z, chunkZ)); } + + //-- chunk region ------------------------------------------------------------------------------------------------// + /** * Maps a {@link BlockRegion} to the chunks that intersect the {@link BlockRegion}. * @@ -219,7 +237,6 @@ public static BlockRegion toChunkRegion(BlockRegion region, Vector3ic chunkPower return toChunkRegion(region, chunkPower.x(), chunkPower.y(), chunkPower.z(), dest); } - /** * Maps a {@link BlockRegion} to the chunks that intersect the {@link BlockRegion}. * This uses the default power ({@link Chunks#POWER_X}, {@link Chunks#POWER_Y}, {@link Chunks#POWER_Z}) @@ -227,11 +244,26 @@ public static BlockRegion toChunkRegion(BlockRegion region, Vector3ic chunkPower * @param region a bounding box that is contained * @param dest will hold the result * @return dest + * @see #toChunkRegion(BlockRegion) */ public static BlockRegion toChunkRegion(BlockRegionc region, BlockRegion dest) { return toChunkRegion(region, Chunks.POWER_X, Chunks.POWER_Y, Chunks.POWER_Z, dest); } + /** + * Maps the {@link BlockRegion} in-place to the region of chunks it intersects. + * + * This uses the default power ({@link Chunks#POWER_X}, {@link Chunks#POWER_Y}, {@link Chunks#POWER_Z}) + * + * @param region a bounding box that is contained + * @return the in-place modified {@code region} + */ + public static BlockRegion toChunkRegion(BlockRegion region) { + return toChunkRegion(region, region); + } + + //-- chunk-relative position -------------------------------------------------------------------------------------// + /** * Returns the internal position of a block within a chunk. * @@ -243,7 +275,6 @@ public static int toRelative(int worldPos, int filter) { return worldPos & filter; } - /** * the relative position from the x axis from the (0,0,0) corner. * @@ -272,6 +303,7 @@ public static int toRelativeY(int blockY) { public static int toRelativeZ(int blockZ) { return toRelative(blockZ, Chunks.INNER_CHUNK_POS_FILTER.z()); } + /** * the relative position in the nearest chunk from the (0,0,0) corner. * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). @@ -279,11 +311,24 @@ public static int toRelativeZ(int blockZ) { * @param worldPos world position * @param dest will hold the result * @return dest + * @see #toRelative(Vector3i) */ public static Vector3i toRelative(Vector3ic worldPos, Vector3i dest) { return toRelative(worldPos.x(), worldPos.y(), worldPos.z(), INNER_CHUNK_POS_FILTER, dest); } + /** + * Compute (in-place) the relative position in the nearest chunk from the (0,0,0) corner. + * + * Default chunk size of ({@link #SIZE_X}, {@link #SIZE_Y}, {@link #SIZE_Z}). + * + * @param worldPos world position + * @return the modified {@code worldPos} vector + */ + public static Vector3i toRelative(Vector3i worldPos) { + return toRelative(worldPos, worldPos); + } + /** * the relative position in the nearest chunk from the (0,0,0) corner. * @@ -311,6 +356,8 @@ public static Vector3i toRelative(int x, int y, int z, Vector3ic chunkFilterSize public static Vector3i toRelative(int x, int y, int z, Vector3i dest) { return dest.set(toRelative(x, INNER_CHUNK_POS_FILTER.x()), toRelative(y, INNER_CHUNK_POS_FILTER.y()), toRelative(z, INNER_CHUNK_POS_FILTER.z())); } + + //-- checks ------------------------------------------------------------------------------------------------------// /** * Works out whether the given block resides inside the given chunk. From 8aeca10df33b0d690a653748829ba54dba17dff9 Mon Sep 17 00:00:00 2001 From: Rasmus Praestholm Date: Sat, 23 Jan 2021 14:07:29 -0600 Subject: [PATCH 145/259] feat: Overhaul game version label content and trigger packaging of an Omega game zip in our new Jenkins (#4409) --- Jenkinsfile | 11 +++ engine/build.gradle | 21 +----- .../terasology/version/TerasologyVersion.java | 73 ++++++++----------- facades/PC/build.gradle.kts | 1 - templates/VERSION | 1 - templates/version.txt | 2 +- 6 files changed, 45 insertions(+), 64 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 755b2b302de..b6b7d5b6828 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,6 +34,17 @@ node ("heavy-java") { } else { println "Running on a branch other than 'master' or 'develop' bypassing publishing" } + + // Trigger the Omega dist job to repackage a game zip with modules + if (env.JOB_NAME.equals("Terasology/engine/develop")) { + build job: 'Terasology/Omega/develop', wait: false + } else if (env.JOB_NAME.equals("Terasology/engine/master")) { + build job: 'Terasology/Omega/master', wait: false + } else if (env.JOB_NAME.equals("Nanoware/Terasology/develop")) { + build job: 'Nanoware/Omega/develop', wait: false + } else if (env.JOB_NAME.equals("Nanoware/Terasology/master")) { + build job: 'Nanoware/Omega/master', wait: false + } } stage('Analytics') { sh "./gradlew --console=plain check spotbugsmain javadoc" diff --git a/engine/build.gradle b/engine/build.gradle index ac56eddbf21..a6449c7ba9f 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -31,20 +31,10 @@ ext { startDateTimeString = dateTimeFormat.format(new Date()) versionInfoFileDir = new File(buildDir, 'classes/org/terasology/version') versionInfoFile = new File(versionInfoFileDir, 'versionInfo.properties') - versionFileName = 'VERSION' versionBase = new File(templatesDir, "version.txt").text.trim() displayVersion = versionBase } -def convertGitBranch = { gitBranch -> - if (gitBranch != null) { - // Remove "origin/" from "origin/develop" - gitBranch.substring(gitBranch.lastIndexOf("/") + 1) - } else { - "" - } -} - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Java Section // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -175,7 +165,7 @@ jar { def manifestClasspath = "$subDirLibs/" + configurations."${sourceSets.main.runtimeClasspathConfigurationName}".collect { it.getName() }.join(" $subDirLibs/") - attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology-" + project.name, "Implementation-Version": env.BUILD_NUMBER + ", " + convertGitBranch(env.GIT_BRANCH) + ", " + env.BUILD_ID + ", " + displayVersion) + attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology", "Implementation-Version": displayVersion + ", engine v" + version + " , build number " + env.BUILD_NUMBER) } } } @@ -230,10 +220,10 @@ group = 'org.terasology.engine' println "Version for $project.name loaded as $version for group $group" -// This version info file actually goes inside the built jar and can be used at runtime +// This version info file actually goes inside the built jar and can be used at runtime - *if* building in Jenkins (JOB_NAME set) task createVersionInfoFile { inputs.property('dateTime', startDateTimeString) - onlyIf { env.BUILD_URL != null } + onlyIf { env.JOB_NAME != null } doLast { versionInfoFileDir.mkdirs() ant.propertyfile(file: versionInfoFile) { @@ -242,8 +232,6 @@ task createVersionInfoFile { ant.entry(key: 'buildTag', value: env.BUILD_TAG) ant.entry(key: 'buildUrl', value: env.BUILD_URL) ant.entry(key: 'jobName', value: env.JOB_NAME) - ant.entry(key: 'gitBranch', value: convertGitBranch(env.GIT_BRANCH)) - ant.entry(key: 'gitCommit', value: env.GIT_COMMIT) ant.entry(key: 'dateTime', value: startDateTimeString) ant.entry(key: 'displayVersion', value: displayVersion) ant.entry(key: 'engineVersion', value: version) @@ -251,8 +239,7 @@ task createVersionInfoFile { } } - -//TODO: Remove it when gestalt will can to handle ProtectionDomain without classes (Resources) +//TODO: Remove this when gestalt can handle ProtectionDomain without classes (Resources) task copyResourcesToClasses(type: Copy) { from sourceSets.main.output.resourcesDir into sourceSets.main.output.classesDirs.first() diff --git a/engine/src/main/java/org/terasology/version/TerasologyVersion.java b/engine/src/main/java/org/terasology/version/TerasologyVersion.java index 55813883d64..68036f2577b 100644 --- a/engine/src/main/java/org/terasology/version/TerasologyVersion.java +++ b/engine/src/main/java/org/terasology/version/TerasologyVersion.java @@ -1,18 +1,6 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2020 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + package org.terasology.version; import org.slf4j.Logger; @@ -22,8 +10,6 @@ import java.io.InputStream; import java.util.Properties; -/** - */ public final class TerasologyVersion { private static final Logger logger = LoggerFactory.getLogger(TerasologyVersion.class); @@ -36,8 +22,7 @@ public final class TerasologyVersion { private static final String BUILD_ID = "buildId"; private static final String BUILD_TAG = "buildTag"; private static final String BUILD_URL = "buildUrl"; - private static final String GIT_BRANCH = "gitBranch"; - private static final String GIT_COMMIT = "gitCommit"; + private static final String JOB_NAME = "jobName"; private static final String DATE_TIME = "dateTime"; private static final String DISPLAY_VERSION = "displayVersion"; private static final String ENGINE_VERSION = "engineVersion"; @@ -48,8 +33,7 @@ public final class TerasologyVersion { private final String buildId; private final String buildTag; private final String buildUrl; - private final String gitBranch; - private final String gitCommit; + private final String jobName; private final String dateTime; private final String toString; private final String displayVersion; @@ -69,8 +53,7 @@ private TerasologyVersion() { buildId = properties.getProperty(BUILD_ID, DEFAULT_VALUE); buildTag = properties.getProperty(BUILD_TAG, DEFAULT_VALUE); buildUrl = properties.getProperty(BUILD_URL, DEFAULT_VALUE); - gitBranch = properties.getProperty(GIT_BRANCH, DEFAULT_VALUE); - gitCommit = properties.getProperty(GIT_COMMIT, DEFAULT_VALUE); + jobName = properties.getProperty(JOB_NAME, DEFAULT_VALUE); dateTime = properties.getProperty(DATE_TIME, DEFAULT_VALUE); displayVersion = properties.getProperty(DISPLAY_VERSION, DEFAULT_VALUE); engineVersion = properties.getProperty(ENGINE_VERSION, DEFAULT_VALUE); @@ -93,13 +76,9 @@ private TerasologyVersion() { toStringBuilder.append("="); toStringBuilder.append(buildUrl); toStringBuilder.append(", "); - toStringBuilder.append(GIT_BRANCH); - toStringBuilder.append("="); - toStringBuilder.append(gitBranch); - toStringBuilder.append(", "); - toStringBuilder.append(GIT_COMMIT); + toStringBuilder.append(JOB_NAME); toStringBuilder.append("="); - toStringBuilder.append(gitCommit); + toStringBuilder.append(jobName); toStringBuilder.append(", "); toStringBuilder.append(DATE_TIME); toStringBuilder.append("="); @@ -139,12 +118,8 @@ public String getBuildUrl() { return buildUrl; } - public String getGitBranch() { - return gitBranch; - } - - public String getGitCommit() { - return gitCommit; + public String getJobName() { + return jobName; } public String getDateTime() { @@ -164,23 +139,33 @@ public String getengineVersion() { * @return prettified version String */ public String getHumanVersion() { - // TODO replace with a nicer version later with full version numbering in place String humanVersion = ""; TerasologyVersion ver = getInstance(); - // MOAR CAPS! + // Game-level release name: Alpha-## until we hit Beta - not engine-specific, but defined here for now if (!ver.getDisplayVersion().trim().equals("")) { - humanVersion = displayVersion.toUpperCase(); - } - - // Expect tag to start with "jenkins-" and remove that - if (ver.getBuildTag().trim().length() > 8) { - humanVersion += " " + ver.getBuildTag().substring(8); + humanVersion = displayVersion.toUpperCase() + " "; } + String formattedDate = ""; // Expect a date string but ignore time of day if (ver.getDateTime().trim().length() > 10) { - humanVersion += " " + ver.getDateTime().substring(0, 10); + formattedDate += ver.getDateTime().substring(0, 10); + } + + // Use the job name from Jenkins to determine which flavor we're dealing with (release, dev build, other) + if (jobName.equals("Terasology/engine/master")) { + // This is a release, hopefully stable, but who knows .. + humanVersion += "Release \n(engine v" + engineVersion + ", build " + buildNumber + ", " + formattedDate + ")"; + } else if (jobName.equals("Terasology/engine/develop")) { + // This is a dev build, so a snapshot for the given release name + humanVersion += "Preview \n(engine v" + engineVersion + ", dev build " + buildNumber + ", " + formattedDate + ")"; + } else if (!jobName.equals("")) { + // This is some other actual build that came from Jenkins + humanVersion += "Special: " + jobName + "\n(engine v" + engineVersion + ", build " + buildNumber + ", " + formattedDate + ")"; + } else { + // Likely this didn't come from Jenkins at all + humanVersion += "Custom version - running from source or hand-built"; } return humanVersion; diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 29d6b33a659..9f2f5349d5e 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -210,7 +210,6 @@ tasks.register("createVersionFile") { expand(mapOf( "buildNumber" to env["BUILD_NUMBER"], "buildUrl" to env["BUILD_URL"], - "gitBranch" to env["GIT_BRANCH"], "dateTime" to startDateTimeString, "displayVersion" to displayVersion )) diff --git a/templates/VERSION b/templates/VERSION index 08be6c60477..b5011fdcad3 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -4,7 +4,6 @@ Terasology - Version Jenkins: URL: ${buildUrl} Build number: ${buildNumber} -GIT branch: ${gitBranch} Created at: ${dateTime} http://terasology.org diff --git a/templates/version.txt b/templates/version.txt index 7e74e68b2a7..7b77d778620 100644 --- a/templates/version.txt +++ b/templates/version.txt @@ -1 +1 @@ -alpha \ No newline at end of file +alpha-18 From 47e5664de078689ddc82bc07242ff3a0583fb5c5 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Mon, 25 Jan 2021 17:00:47 +0000 Subject: [PATCH 146/259] Render even chunks that are next to unloaded chunks. (#4427) --- .../rendering/world/RenderableWorldImpl.java | 7 ++ .../LocalChunkProvider.java | 3 - .../RemoteChunkProvider.java | 3 - .../world/internal/ChunkViewCoreImpl.java | 103 ++++++++++-------- 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index 1ebce6d80c4..8da80748ba6 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -25,6 +25,7 @@ import org.terasology.config.Config; import org.terasology.config.RenderingConfig; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; +import org.terasology.joml.geom.AABBi; import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import org.terasology.monitoring.PerformanceMonitor; @@ -112,6 +113,12 @@ public void onChunkLoaded(Vector3ic chunkCoordinates) { logger.warn("Warning: onChunkLoaded called for a null chunk!"); } } + for (Vector3ic pos : new BlockRegion(chunkCoordinates).expand(1, 1, 1)) { + Chunk chunk = chunkProvider.getChunk(pos); + if (chunk != null) { + chunk.setDirty(true); + } + } } @Override diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 35d28c49081..7553681d826 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -173,9 +173,6 @@ private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { Chunk[] chunks = new Chunk[region.sizeX() * region.sizeY() * region.sizeZ()]; for (Vector3i chunkPos : region) { Chunk chunk = chunkCache.get(chunkPos); - if (chunk == null) { - return null; - } chunkPos.sub(region.minX(), region.minY(), region.minZ()); int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); chunks[index] = chunk; diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 31ace941a6e..b4bbdaa1abd 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -220,9 +220,6 @@ private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { Chunk[] chunks = new Chunk[region.sizeX() * region.sizeY() * region.sizeZ()]; for (Vector3i chunkPos : region) { Chunk chunk = chunkCache.get(chunkPos); - if (chunk == null) { - return null; - } chunkPos.sub(region.minX(), region.minY(), region.minZ()); int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); chunks[index] = chunk; diff --git a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java index 202049d4281..4c98995f2ba 100644 --- a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java @@ -75,15 +75,16 @@ public Block getBlock(Vector3ic pos) { // TODO: Review @Override public Block getBlock(int blockX, int blockY, int blockZ) { - if (!blockRegion.contains(blockX, blockY, blockZ)) { - return defaultBlock; + if (blockRegion.contains(blockX, blockY, blockZ)) { + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + return chunk.getBlock( + Chunks.toRelative(blockX, chunkFilterSize.x), + Chunks.toRelative(blockY, chunkFilterSize.y), + Chunks.toRelative(blockZ, chunkFilterSize.z)); + } } - - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getBlock( - Chunks.toRelative(blockX, chunkFilterSize.x), - Chunks.toRelative(blockY, chunkFilterSize.y), - Chunks.toRelative(blockZ, chunkFilterSize.z)); + return defaultBlock; } @Override @@ -108,22 +109,24 @@ public byte getLight(Vector3i pos) { @Override public byte getSunlight(int blockX, int blockY, int blockZ) { - if (!blockRegion.contains(blockX, blockY, blockZ)) { - return 0; + if (blockRegion.contains(blockX, blockY, blockZ)) { + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + return chunk.getSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + } } - - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + return 0; } @Override public byte getLight(int blockX, int blockY, int blockZ) { - if (!blockRegion.contains(blockX, blockY, blockZ)) { - return 0; + if (blockRegion.contains(blockX, blockY, blockZ)) { + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + return chunk.getLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + } } - - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + return 0; } @Override @@ -134,11 +137,13 @@ public void setBlock(Vector3ic pos, Block type) { @Override public void setBlock(int blockX, int blockY, int blockZ, Block type) { if (blockRegion.contains(blockX, blockY, blockZ)) { - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setBlock(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), type); - } else { - logger.warn("Attempt to modify block outside of the view"); + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + chunk.setBlock(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), type); + return; + } } + logger.warn("Attempt to modify block outside of the view"); } @Override @@ -149,11 +154,13 @@ public void setLight(Vector3ic pos, byte light) { @Override public void setLight(int blockX, int blockY, int blockZ, byte light) { if (blockRegion.contains(blockX, blockY, blockZ)) { - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); - } else { - logger.warn("Attempted to set light at a position not encompassed by the view"); + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + chunk.setLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); + return; + } } + logger.warn("Attempted to set light at a position not encompassed by the view"); } @Override @@ -164,11 +171,13 @@ public void setSunlight(Vector3ic pos, byte light) { @Override public void setSunlight(int blockX, int blockY, int blockZ, byte light) { if (blockRegion.contains(blockX, blockY, blockZ)) { - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); - } else { - throw new IllegalStateException("Attempted to modify sunlight though an unlocked view"); + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + chunk.setSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); + return; + } } + throw new IllegalStateException("Attempted to set sunlight at a position not encompassed by the view"); } @Override @@ -178,12 +187,13 @@ public int getExtraData(int index, Vector3ic pos) { @Override public int getExtraData(int index, int blockX, int blockY, int blockZ) { - if (!blockRegion.contains(blockX, blockY, blockZ)) { - return 0; + if (blockRegion.contains(blockX, blockY, blockZ)) { + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + return chunk.getExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())); + } } - - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - return chunks[chunkIndex].getExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())); + return 0; } @Override @@ -194,33 +204,34 @@ public void setExtraData(int index, Vector3ic pos, int value) { @Override public void setExtraData(int index, int blockX, int blockY, int blockZ, int value) { if (blockRegion.contains(blockX, blockY, blockZ)) { - int chunkIndex = relChunkIndex(blockX, blockY, blockZ); - chunks[chunkIndex].setExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), value); - } else { - throw new IllegalStateException("Attempted to modify extra data though an unlocked view"); + Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; + if (chunk != null) { + chunk.setExtraData(index, Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), value); + } } + throw new IllegalStateException("Attempted to modify extra data at a position not encompassed by the view"); } @Override public void setDirtyAround(Vector3ic blockPos) { - BlockRegion tmp = new BlockRegion(blockPos).expand(1, 1, 1); - for (Vector3ic pos : Chunks.toChunkRegion(tmp, tmp)) { - chunks[pos.x() + offset.x + chunkRegion.getSizeX() * (pos.z() + offset.z)].setDirty(true); - } + setDirtyAround(new BlockRegion(blockPos)); } @Override public void setDirtyAround(BlockRegionc region) { BlockRegion tmp = new BlockRegion(region).expand(1, 1, 1); - for (Vector3ic pos : Chunks.toChunkRegion(tmp, chunkPower, tmp)) { - chunks[pos.x() + offset.x + chunkRegion.getSizeX() * (pos.z() + offset.z)].setDirty(true); + for (Vector3ic pos : Chunks.toChunkRegion(tmp, tmp)) { + Chunk chunk = chunks[TeraMath.calculate3DArrayIndex(pos.x() + offset.x, pos.y() + offset.y, pos.z() + offset.z, JomlUtil.from(chunkRegion.getSize(new Vector3i())))]; + if (chunk != null) { + chunk.setDirty(true); + } } } @Override public boolean isValidView() { for (Chunk chunk : chunks) { - if (chunk.isDisposed()) { + if (chunk != null && chunk.isDisposed()) { return false; } } From 3a85426338ca7da01869fd32dde222f148a25a38 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 27 Jan 2021 08:28:52 -0800 Subject: [PATCH 147/259] feat(JOML): remove Direction JomlUtil (#4422) --- .../main/java/org/terasology/rendering/cameras/Camera.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java index 6efae2c3427..91c02430952 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/Camera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/Camera.java @@ -24,13 +24,13 @@ */ public abstract class Camera { - protected static final Vector3fc FORWARD = JomlUtil.from(Direction.FORWARD.getVector3f()); + protected static final Vector3fc FORWARD = Direction.FORWARD.asVector3f(); /* CAMERA PARAMETERS */ protected final Vector3f position = new Vector3f(0, 0, 0); - protected final Vector3f up = JomlUtil.from(Direction.UP.getVector3f()); + protected final Vector3f up = new Vector3f(Direction.UP.asVector3f()); protected final Vector3f viewingDirection = new Vector3f(FORWARD); - protected final Vector3f viewingAxis = JomlUtil.from(Direction.LEFT.getVector3f()); + protected final Vector3f viewingAxis = new Vector3f(Direction.LEFT.asVector3f()); protected float viewingAngle; protected float zNear = 0.1f; From 6277899b02cf3e4204234bd45b7015b96b533f9c Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 27 Jan 2021 08:46:42 -0800 Subject: [PATCH 148/259] feat(JOML): migrate ServerImpl (#4423) --- .../network/internal/NetMessageUtil.java | 4 ++-- .../network/internal/ServerImpl.java | 19 +++++++++++-------- .../ChunkReadyListener.java | 4 ++-- .../RemoteChunkProvider.java | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/engine/src/main/java/org/terasology/network/internal/NetMessageUtil.java b/engine/src/main/java/org/terasology/network/internal/NetMessageUtil.java index bc22f4848d3..8e64c7867db 100644 --- a/engine/src/main/java/org/terasology/network/internal/NetMessageUtil.java +++ b/engine/src/main/java/org/terasology/network/internal/NetMessageUtil.java @@ -32,8 +32,8 @@ public final class NetMessageUtil { private NetMessageUtil() { } - public static Vector3i convert(NetData.Vector3iData data) { - return new Vector3i(data.getX(), data.getY(), data.getZ()); + public static org.joml.Vector3i convert(NetData.Vector3iData data) { + return new org.joml.Vector3i(data.getX(), data.getY(), data.getZ()); } public static NetData.Vector3iData convert(Vector3i data) { diff --git a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java index e7c1dc782cf..a332e2ae9b8 100644 --- a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java +++ b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java @@ -14,6 +14,8 @@ import gnu.trove.set.TIntSet; import gnu.trove.set.hash.TIntHashSet; import io.netty.channel.Channel; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.EngineTime; @@ -23,7 +25,7 @@ import org.terasology.entitySystem.entity.internal.EngineEntityManager; import org.terasology.entitySystem.event.Event; import org.terasology.math.ChunkMath; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.JomlUtil; import org.terasology.network.NetMetricSource; import org.terasology.network.NetworkComponent; import org.terasology.network.Server; @@ -45,6 +47,7 @@ import org.terasology.world.block.BlockUriParseException; import org.terasology.world.block.internal.BlockManagerImpl; import org.terasology.world.chunks.Chunk; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkSerializer; import org.terasology.world.chunks.remoteChunkProvider.RemoteChunkProvider; @@ -278,7 +281,7 @@ private void processRemoveEntities(NetData.NetMessage message) { } } } - + /** * Apply the block changes from the message to the local world. */ @@ -292,7 +295,7 @@ private void processBlockChanges(NetData.NetMessage message) { if (worldProvider.isBlockRelevant(pos)) { worldProvider.setBlock(pos, newBlock); } else { - awaitingChunkReadyBlockUpdates.put(ChunkMath.calcChunkPos(pos), blockChange); + awaitingChunkReadyBlockUpdates.put(Chunks.toChunkPos(pos), blockChange); } } } @@ -307,7 +310,7 @@ private void processExtraDataChanges(NetData.NetMessage message) { if (worldProvider.isBlockRelevant(pos)) { worldProvider.setExtraData(extraDataChange.getIndex(), pos, extraDataChange.getNewData()); } else { - awaitingChunkReadyExtraDataUpdates.put(ChunkMath.calcChunkPos(pos), extraDataChange); + awaitingChunkReadyExtraDataUpdates.put(Chunks.toChunkPos(pos), extraDataChange); } } } @@ -315,7 +318,7 @@ private void processExtraDataChanges(NetData.NetMessage message) { private void processInvalidatedChunks(NetData.NetMessage message) { for (NetData.InvalidateChunkMessage chunk : message.getInvalidateChunkList()) { Vector3i chunkPos = NetMessageUtil.convert(chunk.getPos()); - remoteWorldProvider.invalidateChunks(chunkPos); + remoteWorldProvider.invalidateChunks(JomlUtil.from(chunkPos)); awaitingChunkReadyBlockUpdates.removeAll(chunkPos); awaitingChunkReadyExtraDataUpdates.removeAll(chunkPos); } @@ -397,17 +400,17 @@ public NetMetricSource getMetrics() { } @Override - public void onChunkReady(Vector3i chunkPos) { + public void onChunkReady(Vector3ic chunkPos) { WorldProvider worldProvider = CoreRegistry.get(WorldProvider.class); - List updateBlockMessages = awaitingChunkReadyBlockUpdates.removeAll(chunkPos); + List updateBlockMessages = awaitingChunkReadyBlockUpdates.removeAll(new Vector3i(chunkPos)); for (NetData.BlockChangeMessage message : updateBlockMessages) { Vector3i pos = NetMessageUtil.convert(message.getPos()); Block newBlock = blockManager.getBlock((short) message.getNewBlock()); worldProvider.setBlock(pos, newBlock); } - List updateExtraDataMessages = awaitingChunkReadyExtraDataUpdates.removeAll(chunkPos); + List updateExtraDataMessages = awaitingChunkReadyExtraDataUpdates.removeAll(new Vector3i(chunkPos)); for (NetData.ExtraDataChangeMessage message : updateExtraDataMessages) { Vector3i pos = NetMessageUtil.convert(message.getPos()); int newValue = message.getNewData(); diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/ChunkReadyListener.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/ChunkReadyListener.java index e2b525f04f1..05614576c1b 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/ChunkReadyListener.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/ChunkReadyListener.java @@ -16,9 +16,9 @@ package org.terasology.world.chunks.remoteChunkProvider; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3ic; @FunctionalInterface public interface ChunkReadyListener { - void onChunkReady(Vector3i pos); + void onChunkReady(Vector3ic pos); } diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index b4bbdaa1abd..708d4eb045a 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -112,7 +112,7 @@ public void update() { } chunk.markReady(); if (listener != null) { - listener.onChunkReady(chunk.getPosition()); + listener.onChunkReady(chunk.getPosition(new org.joml.Vector3i())); } worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); } From 355ba1e1e683fa7dc8cc23ec129938f6b4edae67 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 27 Jan 2021 09:21:19 -0800 Subject: [PATCH 149/259] feat(JOML): migrate OnChunkGenerated (#4426) --- .../localChunkProvider/LocalChunkProviderTest.java | 4 ++-- .../world/chunks/event/OnChunkGenerated.java | 10 +++++++--- .../chunks/localChunkProvider/LocalChunkProvider.java | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index 3a8e84a4144..3156f8b74b7 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -121,7 +121,7 @@ void testGenerateSingleChunk() throws InterruptedException, ExecutionException, Assertions.assertTrue(mustBeOnGeneratedEvent instanceof OnChunkGenerated, "First world event must be OnChunkGenerated"); Assertions.assertEquals(((OnChunkGenerated) mustBeOnGeneratedEvent).getChunkPos(), - chunkPosition, + JomlUtil.from(chunkPosition), "Chunk position at event not expected"); }, () -> { @@ -150,7 +150,7 @@ void testGenerateSingleChunkWithBlockLifeCycle() throws InterruptedException, Ex Assertions.assertTrue(mustBeOnGeneratedEvent instanceof OnChunkGenerated, "First world event must be OnChunkGenerated"); Assertions.assertEquals(((OnChunkGenerated) mustBeOnGeneratedEvent).getChunkPos(), - chunkPosition, + JomlUtil.from(chunkPosition), "Chunk position at event not expected"); }, () -> { diff --git a/engine/src/main/java/org/terasology/world/chunks/event/OnChunkGenerated.java b/engine/src/main/java/org/terasology/world/chunks/event/OnChunkGenerated.java index 58f5a94a851..11fff805d72 100644 --- a/engine/src/main/java/org/terasology/world/chunks/event/OnChunkGenerated.java +++ b/engine/src/main/java/org/terasology/world/chunks/event/OnChunkGenerated.java @@ -15,8 +15,9 @@ */ package org.terasology.world.chunks.event; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.Vector3i; /** */ @@ -24,11 +25,14 @@ public class OnChunkGenerated implements Event { private Vector3i chunkPos = new Vector3i(); - public OnChunkGenerated(Vector3i chunkPos) { + public OnChunkGenerated() { + } + + public OnChunkGenerated(Vector3ic chunkPos) { this.chunkPos.set(chunkPos); } - public Vector3i getChunkPos() { + public Vector3ic getChunkPos() { return chunkPos; } } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 7553681d826..45c41816edb 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -236,7 +236,7 @@ private void processReadyChunk(final Chunk chunk) { PerformanceMonitor.endActivity(); - worldEntity.send(new OnChunkGenerated(chunk.getPosition())); + worldEntity.send(new OnChunkGenerated(chunk.getPosition(new org.joml.Vector3i()))); } worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); } From 708c5aaa6e76a3e5d691b8162a707f18346b0cf7 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 28 Jan 2021 06:15:56 -0800 Subject: [PATCH 150/259] feat(JOML): remove use of termath methods from Material (#4429) Co-authored-by: Nail Khanipov --- .../headless/assets/HeadlessMaterial.java | 10 -- .../assets/material/BaseMaterial.java | 51 -------- .../rendering/assets/material/Material.java | 114 ------------------ .../rendering/opengl/GLSLMaterial.java | 49 -------- 4 files changed, 224 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMaterial.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMaterial.java index 9ed61be11f3..ca71297ef5f 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMaterial.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessMaterial.java @@ -107,11 +107,6 @@ public void setBoolean(String name, boolean value, boolean currentOnly) { // Do nothing } - @Override - public void setMatrix3(String name, Matrix3f matrix, boolean currentOnly) { - // Do nothing - } - @Override public void setMatrix3(String name, Matrix3fc matrix, boolean currentOnly) { @@ -122,11 +117,6 @@ public void setMatrix3(String name, FloatBuffer buffer, boolean currentOnly) { // Do nothing } - @Override - public void setMatrix4(String name, Matrix4f matrix, boolean currentOnly) { - // Do nothing - } - @Override public void setMatrix4(String name, Matrix4fc matrix, boolean currentOnly) { diff --git a/engine/src/main/java/org/terasology/rendering/assets/material/BaseMaterial.java b/engine/src/main/java/org/terasology/rendering/assets/material/BaseMaterial.java index 96e0f7304d7..918ca68b12d 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/material/BaseMaterial.java +++ b/engine/src/main/java/org/terasology/rendering/assets/material/BaseMaterial.java @@ -22,11 +22,6 @@ import org.joml.Vector4fc; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Matrix3f; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector4f; import org.terasology.rendering.assets.shader.ShaderProgramFeature; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.cameras.Camera; @@ -75,15 +70,9 @@ protected BaseMaterial(ResourceUrn urn, AssetType assetType) { @Override public abstract void setBoolean(String name, boolean value, boolean currentOnly); - @Override - public abstract void setMatrix3(String name, Matrix3f matrix, boolean currentOnly); - @Override public abstract void setMatrix3(String name, FloatBuffer buffer, boolean currentOnly); - @Override - public abstract void setMatrix4(String name, Matrix4f matrix, boolean currentOnly); - @Override public abstract void setMatrix4(String name, FloatBuffer buffer, boolean currentOnly); @@ -120,16 +109,6 @@ public void setFloat2(String name, float f1, float f2) { setFloat2(name, f1, f2, false); } - @Override - public void setFloat2(String name, Vector2f value) { - setFloat2(name, value.x, value.y); - } - - @Override - public void setFloat2(String name, Vector2f value, boolean currentOnly) { - setFloat2(name, value.x, value.y, currentOnly); - } - @Override public void setFloat2(String name, Vector2fc value) { setFloat2(name, value.x(), value.y()); @@ -150,16 +129,6 @@ public void setFloat3(String name, float f1, float f2, float f3) { setFloat3(name, f1, f2, f3, false); } - @Override - public void setFloat3(String name, Vector3f value) { - setFloat3(name, value.x, value.y, value.z); - } - - @Override - public void setFloat3(String name, Vector3f value, boolean currentOnly) { - setFloat3(name, value.x, value.y, value.z, currentOnly); - } - @Override public void setFloat3(String name, Vector3fc value) { setFloat3(name, value.x(), value.y(), value.z()); @@ -180,16 +149,6 @@ public void setFloat4(String name, float f1, float f2, float f3, float f4) { setFloat4(name, f1, f2, f3, f4, false); } - @Override - public void setFloat4(String name, Vector4f value) { - setFloat4(name, value.x, value.y, value.z, value.w); - } - - @Override - public void setFloat4(String name, Vector4f value, boolean currentOnly) { - setFloat4(name, value.x, value.y, value.z, value.w, currentOnly); - } - @Override public void setFloat4(String name, Vector4fc value) { setFloat4(name, value.x(), value.y(), value.z(), value.w()); @@ -215,11 +174,6 @@ public void setBoolean(String name, boolean value) { setBoolean(name, value, false); } - @Override - public void setMatrix3(String name, Matrix3f matrix) { - setMatrix3(name, matrix, false); - } - @Override public void setMatrix3(String name, Matrix3fc matrix) { setMatrix3(name, matrix, false); @@ -230,11 +184,6 @@ public void setMatrix3(String name, FloatBuffer buffer) { setMatrix3(name, buffer, false); } - @Override - public void setMatrix4(String name, Matrix4f matrix) { - setMatrix4(name, matrix, false); - } - @Override public void setMatrix4(String name, Matrix4fc matrix) { setMatrix4(name, matrix, false); diff --git a/engine/src/main/java/org/terasology/rendering/assets/material/Material.java b/engine/src/main/java/org/terasology/rendering/assets/material/Material.java index 26e1eda711f..47336c7ff5b 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/material/Material.java +++ b/engine/src/main/java/org/terasology/rendering/assets/material/Material.java @@ -24,11 +24,6 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Matrix3f; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector4f; import org.terasology.rendering.assets.shader.ShaderProgramFeature; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.cameras.Camera; @@ -110,16 +105,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat2(String name, float f1, float f2, boolean currentOnly); - /** - * Sets a float2 uniform parameter (for all feature permutations) - * - * @param name name of uniform for (float2) - * @param value the {@link Vector2f} to write into uniform - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat2(String, Vector2fc)}. - */ - @Deprecated - public abstract void setFloat2(String name, Vector2f value); /** * Sets a float2 uniform parameter (for all feature permutations) @@ -129,18 +114,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat2(String name, Vector2fc value); - /** - * Sets a float2 uniform parameter - * - * @param name name of uniform for (float2) - * @param value the {@link Vector2f} to write into uniform - * @param currentOnly determines if written to all permutations - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat2(String, Vector2fc, boolean)}. - */ - @Deprecated - public abstract void setFloat2(String name, Vector2f value, boolean currentOnly); - /** * Sets a float2 uniform parameter (for all feature permutations) * @@ -189,16 +162,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat3(String name, float f1, float f2, float f3, boolean currentOnly); - /** - * Sets a float3 uniform parameter (for all feature permutations) - * - * @param name name of uniform for (float3) - * @param value the {@link Vector3fc} to write into uniform - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat3(String, Vector3fc)}. - */ - @Deprecated - public abstract void setFloat3(String name, Vector3f value); /** * Sets a float3 uniform parameter (for all feature permutations) @@ -208,16 +171,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat3(String name, Vector3fc value); - /** - * Sets a float3 uniform parameter - * - * @param name name of uniform for (float3) - * @param value the {@link Vector3f} to write into uniform - * @param currentOnly determines if written to all permutations - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat3(String, Vector3fc, boolean)}. - */ - public abstract void setFloat3(String name, Vector3f value, boolean currentOnly); /** * Sets a float3 uniform parameter @@ -269,17 +222,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat4(String name, float f1, float f2, float f3, float f4, boolean currentOnly); - /** - * Sets a float4 uniform parameter (for all feature permutations) - * - * @param name name of uniform for (float4) - * @param value the {@link Vector4f} to write into uniform - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat4(String, Vector4fc)}. - */ - @Deprecated - public abstract void setFloat4(String name, Vector4f value); - /** * Sets a float4 uniform parameter * @@ -288,18 +230,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setFloat4(String name, Vector4fc value); - /** - * Sets a float4 uniform parameter - * - * @param name name of uniform for (float4) - * @param value the {@link Vector4f} to write into uniform - * @param currentOnly determines if written to all permutations - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #setFloat4(String, Vector4fc, boolean)}. - */ - @Deprecated - public abstract void setFloat4(String name, Vector4f value, boolean currentOnly); - /** * Sets a float4 uniform parameter * @@ -358,17 +288,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setBoolean(String name, boolean value, boolean currentOnly); - /** - * Sets a matrix3 uniform parameter (for all feature permutations) - * - * @param name uniform parameter (mat3) - * @param matrix the {@link Matrix3f} to write into uniform - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setMatrix3(String, Matrix3fc)}. - */ - @Deprecated - public abstract void setMatrix3(String name, Matrix3f matrix); - /** * Sets a matrix3 uniform parameter (for all feature permutations) * @@ -377,16 +296,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setMatrix3(String name, Matrix3fc matrix); - /** - * Sets a matrix3 uniform parameter (for all feature permutations) - * @param name uniform parameter (mat3) - * @param matrix write 9 entries from {@link FloatBuffer} into uniform - * @param currentOnly determines if written to all permutations - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setMatrix3(String, Matrix3fc, boolean)}. - */ - @Deprecated - public abstract void setMatrix3(String name, Matrix3f matrix, boolean currentOnly); /** * Sets a matrix3 uniform parameter (for all feature permutations) @@ -413,17 +322,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setMatrix3(String name, FloatBuffer buffer, boolean currentOnly); - /** - * Sets a matrix4 uniform parameter (for all feature permutations) - * - * @param name uniform parameter (mat4) - * @param matrix the {@link Matrix4f} to write into uniform - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setMatrix4(String, Matrix4fc)}. - */ - @Deprecated - public abstract void setMatrix4(String name, Matrix4f matrix); - /** * Sets a matrix4 uniform parameter (for all feature permutations) * @@ -432,18 +330,6 @@ protected Material(ResourceUrn urn, AssetType assetType) { */ public abstract void setMatrix4(String name, Matrix4fc matrix); - /** - * - * @param name uniform parameter (mat4) - * @param matrix the {@link Matrix4f} to write into uniform - * @param currentOnly determines if written to all permutations - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setMatrix4(String, Matrix4fc, boolean)}. - */ - @Deprecated - public abstract void setMatrix4(String name, Matrix4f matrix, boolean currentOnly); - - /** * Sets a matrix4 uniform parameter (for all feature permutations) * diff --git a/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java b/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java index 535f627ba88..6f43c64d408 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/GLSLMaterial.java @@ -36,9 +36,6 @@ import org.terasology.assets.ResourceUrn; import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; -import org.terasology.math.MatrixUtils; -import org.terasology.math.geom.Matrix3f; -import org.terasology.math.geom.Matrix4f; import org.terasology.registry.CoreRegistry; import org.terasology.rendering.ShaderManager; import org.terasology.rendering.assets.material.BaseMaterial; @@ -486,29 +483,6 @@ public void setBoolean(String desc, boolean value, boolean currentOnly) { } } - @Override - public void setMatrix3(String desc, Matrix3f value, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix3fv(id, false, MatrixUtils.matrixToFloatBuffer(value)); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix3fv(id, false, MatrixUtils.matrixToFloatBuffer(value)); - } - - restoreStateAfterUniformsSet(); - } - } - @Override public void setMatrix3(String desc, Matrix3fc value, boolean currentOnly) { if (isDisposed()) { @@ -557,29 +531,6 @@ public void setMatrix3(String desc, FloatBuffer value, boolean currentOnly) { } } - @Override - public void setMatrix4(String desc, Matrix4f value, boolean currentOnly) { - if (isDisposed()) { - return; - } - if (currentOnly) { - enable(); - int id = getUniformLocation(getActiveShaderProgramId(), desc); - GL20.glUniformMatrix4fv(id, false, MatrixUtils.matrixToFloatBuffer(value)); - } else { - TIntIntIterator it = disposalAction.shaderPrograms.iterator(); - while (it.hasNext()) { - it.advance(); - - GL20.glUseProgram(it.value()); - int id = getUniformLocation(it.value(), desc); - GL20.glUniformMatrix4fv(id, false, MatrixUtils.matrixToFloatBuffer(value)); - } - - restoreStateAfterUniformsSet(); - } - } - @Override public void setMatrix4(String desc, Matrix4fc value, boolean currentOnly) { if (isDisposed()) { From 530bde287a26b66ac764849329c9eba37b897eea Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Thu, 28 Jan 2021 21:54:11 +0300 Subject: [PATCH 151/259] perf(world): implement `deflate` for sparse TeraArray (8/16 bit) (#4433) * perf(tera-array): implement `deflate` for sparse arrays 8bit and 16bit. This saves around 20% ram memory for chunks at initial stage. (Tested at same world with view distance 13x7x13(1183 chunks). 257MB before versus 200MB after. Commit affects `ChunkImpl#lighdata`, `ChunkImpl#sunlightData`, `ChunkImpl#blockData`, `ChunkImpl#extraBlockData` * chore(tera-array): fix lgtm's issues. --- .../chunks/deflate/TeraStandardDeflator.java | 134 ++++++++++++++---- 1 file changed, 107 insertions(+), 27 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/deflate/TeraStandardDeflator.java b/engine/src/main/java/org/terasology/world/chunks/deflate/TeraStandardDeflator.java index a2c8aa36e35..ef67d303e9a 100644 --- a/engine/src/main/java/org/terasology/world/chunks/deflate/TeraStandardDeflator.java +++ b/engine/src/main/java/org/terasology/world/chunks/deflate/TeraStandardDeflator.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks.deflate; @@ -24,8 +11,7 @@ /** * TeraStandardDeflator implements a simple deflation algorithm for 4, 8 and 16-bit dense and sparse arrays.
* NOTE: Currently it is optimized for chunks of size 16x256x16 blocks.
- * TODO: Implement deflation for sparse arrays. - * + * TODO: Implement deflation for sparse array 4bit. */ public class TeraStandardDeflator extends TeraVisitingDeflator { @@ -67,7 +53,11 @@ public TeraStandardDeflator() { } @Override - public TeraArray deflateDenseArray16Bit(short[] data, int rowSize, int sizeX, int sizeY, int sizeZ) { + public TeraArray deflateDenseArray16Bit(short[] data, + int rowSize, + int sizeX, + int sizeY, + int sizeZ) { final short[][] inflated = new short[sizeY][]; final short[] deflated = new short[sizeY]; int packed = 0; @@ -110,7 +100,11 @@ public TeraArray deflateDenseArray16Bit(short[] data, int rowSize, int sizeX, in } @Override - public TeraArray deflateDenseArray8Bit(final byte[] data, final int rowSize, final int sizeX, final int sizeY, final int sizeZ) { + public TeraArray deflateDenseArray8Bit(final byte[] data, + final int rowSize, + final int sizeX, + final int sizeY, + final int sizeZ) { final byte[][] inflated = new byte[sizeY][]; final byte[] deflated = new byte[sizeY]; int packed = 0; @@ -153,7 +147,11 @@ public TeraArray deflateDenseArray8Bit(final byte[] data, final int rowSize, fin } @Override - public TeraArray deflateDenseArray4Bit(final byte[] data, final int rowSize, final int sizeX, final int sizeY, final int sizeZ) { + public TeraArray deflateDenseArray4Bit(final byte[] data, + final int rowSize, + final int sizeX, + final int sizeY, + final int sizeZ) { final byte[][] inflated = new byte[sizeY][]; final byte[] deflated = new byte[sizeY]; int packed = 0; @@ -196,19 +194,101 @@ public TeraArray deflateDenseArray4Bit(final byte[] data, final int rowSize, fin } @Override - public TeraArray deflateSparseArray16Bit(short[][] inflated, short[] deflated, short fill, int rowSize, int sizeX, int sizeY, int sizeZ) { - return null; + public TeraArray deflateSparseArray16Bit(short[][] inflated, + short[] deflated, + short fill, + int rowSize, + int sizeX, + int sizeY, + int sizeZ) { + if (inflated == null && deflated == null) { + return new TeraSparseArray16Bit(sizeX, sizeY, sizeZ, fill); + } + if (inflated == null) { + return new TeraSparseArray16Bit(sizeX, sizeY, sizeZ, inflated, deflated); + } + + short[] packed = new short[sizeY]; + short[][] newInflated = new short[sizeY][]; + for (int y = 0; y < sizeY; y++) { + short[] planeXY = inflated[y]; + if (planeXY != null) { + short first = planeXY[0]; + boolean packing = true; + for (int i = 1; i < rowSize; i++) { + if (first != planeXY[i]) { + packing = false; + break; + } + } + if (packing) { + packed[y] = first; + } else { + short[] xyvalues = new short[rowSize]; + System.arraycopy(inflated[y], 0, xyvalues, 0, rowSize); + newInflated[y] = xyvalues; + } + } else { + if (deflated != null) { + packed[y] = deflated[y]; + } + } + } + return new TeraSparseArray16Bit(sizeX, sizeY, sizeZ, newInflated, packed); } @Override - public TeraArray deflateSparseArray8Bit(final byte[][] inflated, final byte[] deflated, final byte fill, final int rowSize, - final int sizeX, final int sizeY, final int sizeZ) { - return null; + public TeraArray deflateSparseArray8Bit(final byte[][] inflated, + final byte[] deflated, + final byte fill, + final int rowSize, + final int sizeX, + final int sizeY, + final int sizeZ) { + if (inflated == null && deflated == null) { + return new TeraSparseArray8Bit(sizeX, sizeY, sizeZ, fill); + } + if (inflated == null) { + return new TeraSparseArray8Bit(sizeX, sizeY, sizeZ, inflated, deflated); + } + + byte[] packed = new byte[sizeY]; + byte[][] newInflated = new byte[sizeY][]; + for (int y = 0; y < sizeY; y++) { + byte[] planeXY = inflated[y]; + if (planeXY != null) { + byte first = planeXY[0]; + boolean packing = true; + for (int i = 1; i < rowSize; i++) { + if (first != planeXY[i]) { + packing = false; + break; + } + } + if (packing) { + packed[y] = first; + } else { + byte[] xyvalues = new byte[rowSize]; + System.arraycopy(inflated[y], 0, xyvalues, 0, rowSize); + newInflated[y] = xyvalues; + } + } else { + if (deflated != null) { + packed[y] = deflated[y]; + } + } + } + return new TeraSparseArray8Bit(sizeX, sizeY, sizeZ, newInflated, packed); } @Override - public TeraArray deflateSparseArray4Bit(final byte[][] inflated, final byte[] deflated, final byte fill, final int rowSize, - final int sizeX, final int sizeY, final int sizeZ) { + public TeraArray deflateSparseArray4Bit(final byte[][] inflated, + final byte[] deflated, + final byte fill, + final int rowSize, + final int sizeX, + final int sizeY, + final int sizeZ) { return null; } From 70e70da505027087491901523b050ddf688c069d Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 28 Jan 2021 11:22:29 -0800 Subject: [PATCH 152/259] feat(JOML): migrate texture atlas (#4425) --- .../assets/atlas/AtlasDefinition.java | 2 +- .../rendering/assets/atlas/AtlasFormat.java | 48 +++++++++++-------- .../assets/atlas/FreeformDefinition.java | 3 +- .../assets/atlas/GridDefinition.java | 3 +- .../assets/texture/subtexture/Subtexture.java | 8 ++-- .../texture/subtexture/SubtextureData.java | 8 ++-- .../world/block/internal/BlockBuilder.java | 6 +-- .../world/block/tiles/NullWorldAtlas.java | 2 +- .../world/block/tiles/WorldAtlas.java | 2 +- .../world/block/tiles/WorldAtlasImpl.java | 20 ++++---- 10 files changed, 56 insertions(+), 46 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasDefinition.java b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasDefinition.java index 118dfe3a4a1..4f6f0aface1 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasDefinition.java +++ b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasDefinition.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.assets.atlas; -import org.terasology.math.geom.Vector2i; +import org.joml.Vector2i; import java.util.List; diff --git a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java index e57949a76b7..e876060e47c 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java +++ b/engine/src/main/java/org/terasology/rendering/assets/atlas/AtlasFormat.java @@ -19,6 +19,9 @@ import com.google.common.collect.Maps; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector2ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; @@ -26,13 +29,11 @@ import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; -import org.terasology.math.geom.Rect2f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector2i; +import org.terasology.joml.geom.Rectanglef; import org.terasology.naming.Name; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.assets.texture.subtexture.SubtextureData; -import org.terasology.utilities.gson.legacy.LegacyVector2iTypeAdapter; +import org.terasology.utilities.gson.Vector2iTypeAdapter; import java.io.IOException; import java.io.InputStreamReader; @@ -55,7 +56,7 @@ public class AtlasFormat extends AbstractAssetFileFormat { public AtlasFormat(AssetManager assetManager) { super("atlas"); this.assetManager = assetManager; - gson = new GsonBuilder().registerTypeAdapter(Vector2i.class, new LegacyVector2iTypeAdapter()).create(); + gson = new GsonBuilder().registerTypeAdapter(Vector2i.class, new Vector2iTypeAdapter()).create(); } @Override @@ -93,7 +94,7 @@ public AtlasData load(ResourceUrn urn, List inputs) throws IOExce } - private void process(FreeformDefinition freeform, Texture texture, Vector2i size, Map out) { + private void process(FreeformDefinition freeform, Texture texture, Vector2ic size, Map out) { if (freeform.getName() == null || freeform.getName().isEmpty()) { logger.error("Bad subimage definition - missing mandatory property name"); return; @@ -106,17 +107,20 @@ private void process(FreeformDefinition freeform, Texture texture, Vector2i size logger.error("Bad subimage definition '{}' - requires one of max or size", freeform.getName()); return; } - Vector2f min = new Vector2f((float) freeform.getMin().x / size.x, (float) freeform.getMin().y / size.y); + Vector2f min = new Vector2f((float) freeform.getMin().x / size.x(), (float) freeform.getMin().y / size.y()); if (freeform.getSize() != null) { - Vector2f itemSize = new Vector2f((float) freeform.getSize().x / size.x, (float) freeform.getSize().y / size.y); - out.put(new Name(freeform.getName()), new SubtextureData(texture, shrinkRegion(Rect2f.createFromMinAndSize(min, itemSize)))); + Vector2f itemSize = new Vector2f((float) freeform.getSize().x / size.x(), + (float) freeform.getSize().y / size.y()); + + out.put(new Name(freeform.getName()), new SubtextureData(texture, + shrinkRegion(new Rectanglef(min, min).setSize(itemSize)))); } else if (freeform.getMax() != null) { - Vector2f max = new Vector2f((float) freeform.getMax().x / size.x, (float) freeform.getMax().y / size.y); - out.put(new Name(freeform.getName()), new SubtextureData(texture, shrinkRegion(Rect2f.createFromMinAndMax(min, max)))); + Vector2f max = new Vector2f((float) freeform.getMax().x / size.x(), (float) freeform.getMax().y / size.y()); + out.put(new Name(freeform.getName()), new SubtextureData(texture, shrinkRegion(new Rectanglef(min, max)))); } } - private void process(GridDefinition grid, Texture texture, Vector2i size, Map out) { + private void process(GridDefinition grid, Texture texture, Vector2ic size, Map out) { if (grid.getTileSize() == null) { logger.error("Bad grid definition - missing mandatory property tileSize"); return; @@ -128,9 +132,10 @@ private void process(GridDefinition grid, Texture texture, Vector2i size, Map { private Texture texture; - private Rect2f subregion; + private Rectanglef subregion; private Runnable disposalAction; public Subtexture(ResourceUrn urn, AssetType assetType, SubtextureData data) { @@ -65,7 +65,7 @@ public Texture getTexture() { @Override public Rectanglef getRegion() { - return JomlUtil.from(subregion); + return subregion; } @Override @@ -77,12 +77,12 @@ public Rectanglei getPixelRegion() { @Override public int getWidth() { - return TeraMath.ceilToInt(texture.getWidth() * subregion.width()); + return TeraMath.ceilToInt(texture.getWidth() * subregion.getSizeX()); } @Override public int getHeight() { - return TeraMath.ceilToInt(texture.getHeight() * subregion.height()); + return TeraMath.ceilToInt(texture.getHeight() * subregion.getSizeY()); } @Override diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/SubtextureData.java b/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/SubtextureData.java index 4cb2deee0e5..e1b3ffe17ec 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/SubtextureData.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/subtexture/SubtextureData.java @@ -16,16 +16,16 @@ package org.terasology.rendering.assets.texture.subtexture; import org.terasology.assets.AssetData; -import org.terasology.math.geom.Rect2f; +import org.terasology.joml.geom.Rectanglef; import org.terasology.rendering.assets.texture.Texture; /** */ public class SubtextureData implements AssetData { private Texture texture; - private Rect2f region; + private Rectanglef region; - public SubtextureData(Texture texture, Rect2f region) { + public SubtextureData(Texture texture, Rectanglef region) { this.texture = texture; this.region = region; } @@ -34,7 +34,7 @@ public Texture getTexture() { return texture; } - public Rect2f getRegion() { + public Rectanglef getRegion() { return region; } diff --git a/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java b/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java index 470d679703e..22bc0103484 100644 --- a/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java +++ b/engine/src/main/java/org/terasology/world/block/internal/BlockBuilder.java @@ -189,7 +189,7 @@ private BlockAppearance createAppearance(BlockShape shape, Map tiles) { if (blockTile != null) { BlockMeshPart lowMeshPart = lowShape .getMeshPart(part) - .mapTexCoords(JomlUtil.from(worldAtlas.getTexCoords(blockTile, true)), worldAtlas.getRelativeTileSize(), blockTile.getLength()); + .mapTexCoords(worldAtlas.getTexCoords(blockTile, true), worldAtlas.getRelativeTileSize(), blockTile.getLength()); block.setLowLiquidMesh(part.getSide(), lowMeshPart); BlockMeshPart topMeshPart = topShape .getMeshPart(part) - .mapTexCoords(JomlUtil.from(worldAtlas.getTexCoords(blockTile, true)), worldAtlas.getRelativeTileSize(), blockTile.getLength()); + .mapTexCoords(worldAtlas.getTexCoords(blockTile, true), worldAtlas.getRelativeTileSize(), blockTile.getLength()); block.setTopLiquidMesh(part.getSide(), topMeshPart); } } diff --git a/engine/src/main/java/org/terasology/world/block/tiles/NullWorldAtlas.java b/engine/src/main/java/org/terasology/world/block/tiles/NullWorldAtlas.java index d6116aea07a..97a05de3054 100644 --- a/engine/src/main/java/org/terasology/world/block/tiles/NullWorldAtlas.java +++ b/engine/src/main/java/org/terasology/world/block/tiles/NullWorldAtlas.java @@ -16,8 +16,8 @@ package org.terasology.world.block.tiles; +import org.joml.Vector2f; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Vector2f; /** * Dummy implementation of WorldAtlas diff --git a/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlas.java b/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlas.java index 9d0ed76ccc3..1271ec603b3 100644 --- a/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlas.java +++ b/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlas.java @@ -16,8 +16,8 @@ package org.terasology.world.block.tiles; +import org.joml.Vector2f; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Vector2f; import org.terasology.module.sandbox.API; /** diff --git a/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlasImpl.java b/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlasImpl.java index 3250f80e84e..0deb34799d9 100644 --- a/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlasImpl.java +++ b/engine/src/main/java/org/terasology/world/block/tiles/WorldAtlasImpl.java @@ -22,13 +22,13 @@ import de.matthiasmann.twl.utils.PNGDecoder; import gnu.trove.map.TObjectIntMap; import gnu.trove.map.hash.TObjectIntHashMap; +import org.joml.Vector2f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; import org.terasology.engine.paths.PathManager; +import org.terasology.joml.geom.Rectanglef; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Rect2f; -import org.terasology.math.geom.Vector2f; import org.terasology.naming.Name; import org.terasology.rendering.assets.atlas.Atlas; import org.terasology.rendering.assets.atlas.AtlasData; @@ -40,7 +40,9 @@ import org.terasology.utilities.Assets; import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -117,7 +119,7 @@ public Vector2f getTexCoords(BlockTile tile, boolean warnOnError) { /** * Obtains the tex coords of a block tile. If it isn't part of the atlas it is added to the atlas. * - * @param uri The uri of the block tile of interest. + * @param uri The uri of the block tile of interest. * @param warnOnError Whether a warning should be logged if the asset canot be found * @return The tex coords of the tile in the atlas. */ @@ -185,9 +187,9 @@ private int indexTile(ResourceUrn uri) { } private boolean checkTile(BlockTile tile) { - for (int i=0; i list, Stri } } // intentionally pad this list with null so that the indexes match the main atlas - for (int i=0; i { Vector2f coords = getTexCoords(index); - SubtextureData subtextureData = new SubtextureData(texture, Rect2f.createFromMinAndSize(coords, texSize)); + SubtextureData subtextureData = new SubtextureData(texture, new Rectanglef(coords, coords).setSize(texSize)); Map textureAtlas = textureAtlases.get(tileUri.getModuleName()); if (textureAtlas == null) { @@ -348,7 +350,7 @@ private BufferedImage generateAtlas(int mipMapLevel, List tileImages, g.setColor(clearColor); g.fillRect(0, 0, size, size); - + int totalIndex = 0; for (int tileIndex = 0; tileIndex < tileImages.size(); tileIndex++) { BlockTile tile = tileImages.get(tileIndex); From 8cb1efbe38aba6fd9487f164ebdd6e8f5fd5e811 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 28 Jan 2021 12:04:31 -0800 Subject: [PATCH 153/259] feat(JOML): migrate setBlock(Map) (#4428) --- .../entity/placement/BlockPlacingSystem.java | 3 +-- .../block/entity/placement/PlaceBlocks.java | 3 ++- .../structure/AttachSupportRequired.java | 19 ++++++++------- .../structure/BlockDefSupportRequired.java | 7 +++--- .../structure/BlockStructuralSupport.java | 3 ++- .../BlockStructuralSupportSystem.java | 7 +++--- .../structure/SideBlockSupportRequired.java | 21 ++++++++-------- .../AbstractWorldProviderDecorator.java | 2 +- .../internal/EntityAwareWorldProvider.java | 8 +++---- .../world/internal/WorldProviderCore.java | 6 ++--- .../world/internal/WorldProviderCoreImpl.java | 24 ++++++++++--------- 11 files changed, 55 insertions(+), 48 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java b/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java index 259f9ab9130..cc80bae93a6 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/placement/BlockPlacingSystem.java @@ -21,7 +21,6 @@ import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; -import org.terasology.math.JomlUtil; import org.terasology.registry.In; import org.terasology.world.WorldComponent; import org.terasology.world.WorldProvider; @@ -35,6 +34,6 @@ public class BlockPlacingSystem extends BaseComponentSystem { @ReceiveEvent(components = {WorldComponent.class}, priority = EventPriority.PRIORITY_TRIVIAL) public void placeBlockInWorld(PlaceBlocks event, EntityRef world) { - worldProvider.setBlocks(JomlUtil.blockMap(event.getBlocks())); + worldProvider.setBlocks(event.getBlocks()); } } diff --git a/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java b/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java index 284e6e875ba..8e94a18bc1d 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java +++ b/engine/src/main/java/org/terasology/world/block/entity/placement/PlaceBlocks.java @@ -16,6 +16,7 @@ package org.terasology.world.block.entity.placement; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.AbstractConsumableEvent; import org.terasology.world.block.Block; @@ -47,7 +48,7 @@ public PlaceBlocks(Map blocks, EntityRef instigator) { this.instigator = instigator; } - public Map getBlocks() { + public Map getBlocks() { return Collections.unmodifiableMap(blocks); } diff --git a/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java index 2ba27b51f74..01d82695403 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/AttachSupportRequired.java @@ -16,6 +16,7 @@ package org.terasology.world.block.structure; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.Side; import org.terasology.registry.CoreRegistry; @@ -36,9 +37,9 @@ public int getPriority() { @Override public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { - final AttachSupportRequiredComponent component = getComponent(location, Collections.emptyMap()); + final AttachSupportRequiredComponent component = getComponent(location, Collections.emptyMap()); if (component != null) { - final Block block = getBlockWithOverrides(location, Collections.emptyMap()); + final Block block = getBlockWithOverrides(location, Collections.emptyMap()); if (!hasRequiredSupportOnSideForBlock(location, sideChanged, block)) { return true; } @@ -46,11 +47,11 @@ public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { return false; } - private boolean hasRequiredSupportOnSideForBlock(Vector3i location, Side sideChanged, Block block) { + private boolean hasRequiredSupportOnSideForBlock(Vector3ic location, Side sideChanged, Block block) { final BlockMeshPart part = block.getPrimaryAppearance().getPart(BlockPart.fromSide(sideChanged)); if (part != null) { // This block has mesh on this side, therefore it requires a support on that side - if (!hasSupportFromBlockOnSide(location, sideChanged, Collections.emptyMap())) { + if (!hasSupportFromBlockOnSide(location, sideChanged, Collections.emptyMap())) { return false; } } @@ -58,7 +59,7 @@ private boolean hasRequiredSupportOnSideForBlock(Vector3i location, Side sideCha } @Override - public boolean isSufficientlySupported(Vector3i location, Map blockOverrides) { + public boolean isSufficientlySupported(Vector3ic location, Map blockOverrides) { final AttachSupportRequiredComponent component = getComponent(location, blockOverrides); if (component != null) { final Block block = getBlockWithOverrides(location, blockOverrides); @@ -72,7 +73,7 @@ public boolean isSufficientlySupported(Vector3i location, Map b return true; } - private EntityRef getEntity(Vector3i location, Map blockOverrides) { + private EntityRef getEntity(Vector3ic location, Map blockOverrides) { final Block overwrittenBlock = blockOverrides.get(location); if (overwrittenBlock != null) { return overwrittenBlock.getEntity(); @@ -85,11 +86,11 @@ private EntityRef getEntity(Vector3i location, Map blockOverrid } } - private AttachSupportRequiredComponent getComponent(Vector3i location, Map blockOverrides) { + private AttachSupportRequiredComponent getComponent(Vector3ic location, Map blockOverrides) { return getEntity(location, blockOverrides).getComponent(AttachSupportRequiredComponent.class); } - private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map blockOverrides) { + private boolean hasSupportFromBlockOnSide(Vector3ic blockPosition, Side side, Map blockOverrides) { final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition, new Vector3i()); if (!getWorldProvider().isBlockRelevant(sideBlockPosition)) { return true; @@ -97,7 +98,7 @@ private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map return getBlockWithOverrides(sideBlockPosition, blockOverrides).canAttachTo(side.reverse()); } - private Block getBlockWithOverrides(Vector3i location, Map blockOverrides) { + private Block getBlockWithOverrides(Vector3ic location, Map blockOverrides) { final Block blockFromOverride = blockOverrides.get(location); if (blockFromOverride != null) { return blockFromOverride; diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java index 62ab7a78b99..50ed7c1d9bc 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockDefSupportRequired.java @@ -16,6 +16,7 @@ package org.terasology.world.block.structure; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.math.Side; import org.terasology.registry.CoreRegistry; import org.terasology.world.WorldProvider; @@ -31,7 +32,7 @@ public int getPriority() { } @Override - public boolean isSufficientlySupported(Vector3i location, Map blockOverrides) { + public boolean isSufficientlySupported(Vector3ic location, Map blockOverrides) { final Block block = getBlockWithOverrides(location, blockOverrides); if (block.isSupportRequired()) { final Vector3i bottomLocation = Side.BOTTOM.getAdjacentPos(location, new Vector3i()); @@ -43,10 +44,10 @@ public boolean isSufficientlySupported(Vector3i location, Map b @Override public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { - return sideChanged == Side.BOTTOM && !isSufficientlySupported(location, Collections.emptyMap()); + return sideChanged == Side.BOTTOM && !isSufficientlySupported(location, Collections.emptyMap()); } - private Block getBlockWithOverrides(Vector3i location, Map blockOverrides) { + private Block getBlockWithOverrides(Vector3ic location, Map blockOverrides) { final Block blockFromOverride = blockOverrides.get(location); if (blockFromOverride != null) { return blockFromOverride; diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java index 06c9e28feed..d8c0b2a6d51 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupport.java @@ -16,6 +16,7 @@ package org.terasology.world.block.structure; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.math.Side; import org.terasology.world.block.Block; @@ -46,5 +47,5 @@ public interface BlockStructuralSupport { * @param blockOverrides * @return */ - boolean isSufficientlySupported(Vector3i location, Map blockOverrides); + boolean isSufficientlySupported(Vector3ic location, Map blockOverrides); } diff --git a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java index af1bb0fd263..547fd81b3d1 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java +++ b/engine/src/main/java/org/terasology/world/block/structure/BlockStructuralSupportSystem.java @@ -17,6 +17,7 @@ import com.google.common.collect.Sets; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; @@ -91,10 +92,10 @@ public void checkForSupportRemoved(OnChangedBlock event, EntityRef entity) { @ReceiveEvent public void preventInvalidPlacement(PlaceBlocks placeBlocks, EntityRef world) { - final Map blocksMap = placeBlocks.getBlocks(); + final Map blocksMap = placeBlocks.getBlocks(); for (BlockStructuralSupport support : supports) { - for (Map.Entry blockEntry : blocksMap.entrySet()) { - final Vector3i position = blockEntry.getKey(); + for (Map.Entry blockEntry : blocksMap.entrySet()) { + final Vector3ic position = blockEntry.getKey(); if (!support.isSufficientlySupported(position, Collections.unmodifiableMap(blocksMap))) { placeBlocks.consume(); return; diff --git a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java index 0ebd2ed4c42..c0e32758cc4 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java @@ -16,6 +16,7 @@ package org.terasology.world.block.structure; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.prefab.PrefabManager; @@ -43,9 +44,9 @@ public int getPriority() { @Override public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { - final SideBlockSupportRequiredComponent component = getComponent(location, Collections.emptyMap()); + final SideBlockSupportRequiredComponent component = getComponent(location, Collections.emptyMap()); if (component != null) { - final boolean sufficientlySupported = isSufficientlySupported(location, sideChanged, Collections.emptyMap(), component); + final boolean sufficientlySupported = isSufficientlySupported(location, sideChanged, Collections.emptyMap(), component); if (!sufficientlySupported) { if (component.dropDelay <= 0) { return true; @@ -64,7 +65,7 @@ public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { @ReceiveEvent public void checkForSupport(DelayedActionTriggeredEvent event, EntityRef entity, BlockComponent block, SideBlockSupportRequiredComponent supportRequired) { if (event.getActionId().equals(SUPPORT_CHECK_ACTION_ID)) { - if (!isSufficientlySupported(JomlUtil.from(block.position), null, Collections.emptyMap(), supportRequired)) { + if (!isSufficientlySupported(JomlUtil.from(block.position), null, Collections.emptyMap(), supportRequired)) { PrefabManager prefabManager = CoreRegistry.get(PrefabManager.class); entity.send(new DestroyEvent(entity, EntityRef.NULL, prefabManager.getPrefab("engine:supportRemovedDamage"))); } @@ -72,7 +73,7 @@ public void checkForSupport(DelayedActionTriggeredEvent event, EntityRef entity, } @Override - public boolean isSufficientlySupported(Vector3i location, Map blockOverrides) { + public boolean isSufficientlySupported(Vector3ic location, Map blockOverrides) { final SideBlockSupportRequiredComponent component = getComponent(location, blockOverrides); if (component != null) { return isSufficientlySupported(location, null, blockOverrides, component); @@ -80,7 +81,7 @@ public boolean isSufficientlySupported(Vector3i location, Map b return true; } - private EntityRef getEntity(Vector3i location, Map blockOverrides) { + private EntityRef getEntity(Vector3ic location, Map blockOverrides) { final Block overwrittenBlock = blockOverrides.get(location); if (overwrittenBlock != null) { return overwrittenBlock.getEntity(); @@ -93,11 +94,11 @@ private EntityRef getEntity(Vector3i location, Map blockOverrid } } - private SideBlockSupportRequiredComponent getComponent(Vector3i location, Map blockOverrides) { + private SideBlockSupportRequiredComponent getComponent(Vector3ic location, Map blockOverrides) { return getEntity(location, blockOverrides).getComponent(SideBlockSupportRequiredComponent.class); } - private boolean isSufficientlySupported(Vector3i location, Side sideChanged, Map blockOverrides, SideBlockSupportRequiredComponent supportComponent) { + private boolean isSufficientlySupported(Vector3ic location, Side sideChanged, Map blockOverrides, SideBlockSupportRequiredComponent supportComponent) { if (supportComponent != null) { if ((sideChanged == null || sideChanged.isHorizontal()) && supportComponent.sideAllowed && !hasSupport(location, supportComponent, blockOverrides)) { @@ -110,7 +111,7 @@ private boolean isSufficientlySupported(Vector3i location, Side sideChanged, Map return true; } - private boolean hasSupport(Vector3i blockPosition, SideBlockSupportRequiredComponent supportComponent, Map blockOverrides) { + private boolean hasSupport(Vector3ic blockPosition, SideBlockSupportRequiredComponent supportComponent, Map blockOverrides) { if (supportComponent.bottomAllowed && hasSupportFromBlockOnSide(blockPosition, Side.BOTTOM, blockOverrides)) { return true; } @@ -126,7 +127,7 @@ private boolean hasSupport(Vector3i blockPosition, SideBlockSupportRequiredCompo return false; } - private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map blockOverrides) { + private boolean hasSupportFromBlockOnSide(Vector3ic blockPosition, Side side, Map blockOverrides) { final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition, new Vector3i()); if (!getWorldProvider().isBlockRelevant(sideBlockPosition)) { return true; @@ -134,7 +135,7 @@ private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map return getBlockWithOverrides(sideBlockPosition, blockOverrides).canAttachTo(side.reverse()); } - private Block getBlockWithOverrides(Vector3i location, Map blockOverrides) { + private Block getBlockWithOverrides(Vector3i location, Map blockOverrides) { final Block blockFromOverride = blockOverrides.get(location); if (blockFromOverride != null) { return blockFromOverride; diff --git a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java index 42a7bcf6d50..b9a0bf75cdc 100644 --- a/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java +++ b/engine/src/main/java/org/terasology/world/internal/AbstractWorldProviderDecorator.java @@ -99,7 +99,7 @@ public Block setBlock(Vector3ic pos, Block type) { } @Override - public Map setBlocks(Map blocks) { + public Map setBlocks(Map blocks) { return base.setBlocks(blocks); } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index 8b6197bf0c5..6c478700be6 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -138,10 +138,10 @@ public Block setBlock(Vector3ic pos, Block type) { //However, this means that even if only one block is placed, this is the method being called. //It must be overridden here to allow an OnChangedBlock event to be properly sent for placed blocks. @Override - public Map setBlocks(Map blocks) { + public Map setBlocks(Map blocks) { if (GameThread.isCurrentThread()) { - Map oldBlocks = super.setBlocks(blocks); - for (Vector3i vec : oldBlocks.keySet()) { + Map oldBlocks = super.setBlocks(blocks); + for (Vector3ic vec : oldBlocks.keySet()) { if (oldBlocks.get(vec) != null) { EntityRef blockEntity = getBlockEntityAt(vec); @@ -150,7 +150,7 @@ public Map setBlocks(Map blocks) { Optional.ofNullable(blockEntity.getComponent(RetainComponentsComponent.class)) .map(retainComponentsComponent -> retainComponentsComponent.components) .orElse(Collections.emptySet()); - updateBlockEntity(blockEntity, vec, oldBlocks.get(vec), blocks.get(vec), false, retainComponents); + updateBlockEntity(blockEntity, JomlUtil.from(vec), oldBlocks.get(vec), blocks.get(vec), false, retainComponents); } } return oldBlocks; diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java index 93b70281bfc..d19eb247f41 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCore.java @@ -139,9 +139,9 @@ default Block setBlock(Vector3i pos, Block type) { * @return A mapping from world position to previous block type. * The value of a map entry is Null if the change failed (because the necessary chunk was not loaded) */ - default Map setBlocks(Map blocks) { - Map resultMap = Maps.newHashMap(); - for (Map.Entry entry: blocks.entrySet()) { + default Map setBlocks(Map blocks) { + Map resultMap = Maps.newHashMap(); + for (Map.Entry entry : blocks.entrySet()) { Block oldBlock = setBlock(entry.getKey(), entry.getValue()); resultMap.put(entry.getKey(), oldBlock); } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index 31b17fd96c6..d3fd7617fd9 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -202,32 +202,34 @@ public Block setBlock(Vector3ic worldPos, Block type) { } @Override - public Map setBlocks(Map blocks) { + public Map setBlocks(Map blocks) { /* * Hint: This method has a benchmark available in the BenchmarkScreen, The screen can be opened ingame via the * command "showSCreen BenchmarkScreen". */ Set changedBlocks = new HashSet<>(); - Map result = new HashMap<>(blocks.size()); + Map result = new HashMap<>(blocks.size()); - for (Map.Entry entry : blocks.entrySet()) { - org.terasology.math.geom.Vector3i worldPos = entry.getKey(); - org.terasology.math.geom.Vector3i chunkPos = ChunkMath.calcChunkPos(worldPos); + Vector3i chunkPos = new Vector3i(); + Vector3i relativePos = new Vector3i(); + for (Map.Entry entry : blocks.entrySet()) { + Vector3ic worldPos = entry.getKey(); + Chunks.toChunkPos(worldPos, chunkPos); CoreChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { Block type = entry.getValue(); - org.terasology.math.geom.Vector3i blockPos = ChunkMath.calcRelativeBlockPos(worldPos); - Block oldBlockType = chunk.setBlock(blockPos, type); + Chunks.toRelative(worldPos, relativePos); + Block oldBlockType = chunk.setBlock(relativePos, type); if (oldBlockType != type) { - BlockChange oldChange = blockChanges.get(worldPos); + BlockChange oldChange = blockChanges.get(JomlUtil.from(worldPos)); if (oldChange == null) { - blockChanges.put(worldPos, new BlockChange(JomlUtil.from(worldPos), oldBlockType, type)); + blockChanges.put(JomlUtil.from(worldPos), new BlockChange(worldPos, oldBlockType, type)); } else { oldChange.setTo(type); } - setDirtyChunksNear(JomlUtil.from(worldPos)); - changedBlocks.add(new BlockChange(JomlUtil.from(worldPos), oldBlockType, type)); + setDirtyChunksNear(worldPos); + changedBlocks.add(new BlockChange(worldPos, oldBlockType, type)); } result.put(worldPos, oldBlockType); } else { From 4a0ead14f884a86a3d009ef1da9881246ff57929 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 28 Jan 2021 12:36:12 -0800 Subject: [PATCH 154/259] feat(JOML): migrate Texture (#4424) Co-authored-by: Tobias Nett --- .../engine/subsystem/headless/assets/HeadlessTexture.java | 7 +++---- .../org/terasology/rendering/assets/texture/Texture.java | 8 +++----- .../java/org/terasology/rendering/opengl/OpenGLMesh.java | 1 - .../org/terasology/rendering/opengl/OpenGLTexture.java | 7 +++---- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java index acca5a6cdd6..91887cc598f 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessTexture.java @@ -16,12 +16,11 @@ package org.terasology.engine.subsystem.headless.assets; import com.google.common.collect.Lists; -import org.terasology.joml.geom.Rectanglef; -import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.JomlUtil; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.assets.texture.TextureData; @@ -85,7 +84,7 @@ public Texture getTexture() { @Override public Rectanglef getRegion() { - return JomlUtil.from(FULL_TEXTURE_REGION); + return new Rectanglef(FULL_TEXTURE_REGION); // object is not guarded } @Override diff --git a/engine/src/main/java/org/terasology/rendering/assets/texture/Texture.java b/engine/src/main/java/org/terasology/rendering/assets/texture/Texture.java index 7a98de139f3..3a5213f9f54 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/texture/Texture.java +++ b/engine/src/main/java/org/terasology/rendering/assets/texture/Texture.java @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.terasology.rendering.assets.texture; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Rect2f; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglefc; -/** - */ public abstract class Texture extends TextureRegionAsset { - public static final Rect2f FULL_TEXTURE_REGION = Rect2f.createFromMinAndSize(0, 0, 1, 1); + public static final Rectanglefc FULL_TEXTURE_REGION = new Rectanglef(0, 0, 1, 1); protected Texture(ResourceUrn urn, AssetType assetType) { super(urn, assetType); diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java index ae0d239eb88..6d763479110 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLMesh.java @@ -34,7 +34,6 @@ import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; import org.terasology.joml.geom.AABBf; import org.terasology.joml.geom.AABBfc; -import org.terasology.math.AABB; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.mesh.Mesh; import org.terasology.rendering.assets.mesh.MeshData; diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java index 3609802b277..0bc6d7d2729 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLTexture.java @@ -16,15 +16,14 @@ package org.terasology.rendering.opengl; import com.google.common.collect.Lists; -import org.terasology.joml.geom.Rectanglef; -import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsManager; -import org.terasology.math.JomlUtil; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.assets.texture.TextureData; @@ -182,7 +181,7 @@ public Texture getTexture() { @Override public Rectanglef getRegion() { - return JomlUtil.from(FULL_TEXTURE_REGION); + return new Rectanglef(FULL_TEXTURE_REGION); // object is not guarded } @Override From 00b2c2e4eb6a8a1c23af6ee766c34316ca5ef027 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 28 Jan 2021 23:19:47 -0800 Subject: [PATCH 155/259] feat(JOML): migrate StorageManager (#4421) Co-authored-by: jdrueckert --- .../fixtures/TestStorageManager.java | 11 ++++---- .../internal/StorageManagerTest.java | 8 +++--- .../LocalChunkProviderTest.java | 4 +-- .../persistence/StorageManager.java | 3 ++- .../internal/AbstractStorageManager.java | 26 ++++++++++--------- .../internal/PlayerStoreBuilder.java | 19 +++++++------- .../internal/ReadWriteStorageManager.java | 26 ++++++++++--------- .../LocalChunkProvider.java | 4 +-- 8 files changed, 54 insertions(+), 47 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/fixtures/TestStorageManager.java b/engine-tests/src/test/java/org/terasology/fixtures/TestStorageManager.java index b1822351944..043a5a1ac49 100644 --- a/engine-tests/src/test/java/org/terasology/fixtures/TestStorageManager.java +++ b/engine-tests/src/test/java/org/terasology/fixtures/TestStorageManager.java @@ -3,7 +3,8 @@ package org.terasology.fixtures; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.network.Client; import org.terasology.persistence.ChunkStore; import org.terasology.persistence.PlayerStore; @@ -17,7 +18,7 @@ public class TestStorageManager implements StorageManager { - private final Map chunkStores = new HashMap<>(); + private final Map chunkStores = new HashMap<>(); public TestStorageManager() { } @@ -27,12 +28,12 @@ public TestStorageManager(List chunkList) { chunkList.forEach(this::add); } - public TestStorageManager(Map chunkStores) { + public TestStorageManager(Map chunkStores) { this.chunkStores.putAll(chunkStores); } public void add(Chunk chunk) { - chunkStores.put(chunk.getPosition(), new TestChunkStore(chunk)); + chunkStores.put(chunk.getPosition(new Vector3i()), new TestChunkStore(chunk)); } @Override @@ -56,7 +57,7 @@ public void waitForCompletionOfPreviousSaveAndStartSaving() { } @Override - public ChunkStore loadChunkStore(Vector3i chunkPos) { + public ChunkStore loadChunkStore(Vector3ic chunkPos) { return chunkStores.get(chunkPos); } diff --git a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java index 721c14cbe4a..2818ffef70b 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/internal/StorageManagerTest.java @@ -275,7 +275,7 @@ public void testReferenceRemainsValidOverStorageRestoral() throws Exception { @Test public void testGetUnstoredChunkReturnsNothing() { - esm.loadChunkStore(JomlUtil.from(CHUNK_POS)); + esm.loadChunkStore(CHUNK_POS); } @Test @@ -290,7 +290,7 @@ public void testStoreAndRestoreChunkStore() { esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); - ChunkStore restored = esm.loadChunkStore(JomlUtil.from(CHUNK_POS)); + ChunkStore restored = esm.loadChunkStore(CHUNK_POS); assertNotNull(restored); assertEquals(CHUNK_POS, restored.getChunkPosition()); assertNotNull(restored.getChunk()); @@ -321,7 +321,7 @@ public void testChunkSurvivesStorageSaveAndRestore() throws Exception { recordAndReplayCurrentStatus); newSM.loadGlobalStore(); - ChunkStore restored = newSM.loadChunkStore(JomlUtil.from(CHUNK_POS)); + ChunkStore restored = newSM.loadChunkStore(CHUNK_POS); assertNotNull(restored); assertEquals(CHUNK_POS, restored.getChunkPosition()); assertNotNull(restored.getChunk()); @@ -357,7 +357,7 @@ public void testEntitySurvivesStorageInChunkStore() throws Exception { extraDataManager, false, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore(); - ChunkStore restored = newSM.loadChunkStore(JomlUtil.from(CHUNK_POS)); + ChunkStore restored = newSM.loadChunkStore(CHUNK_POS); restored.restoreEntities(); EntityRef ref = newEntityManager.getEntity(id); assertTrue(ref.exists()); diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index 3156f8b74b7..d1a06fa3a93 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -184,7 +184,7 @@ void testLoadSingleChunk() throws InterruptedException, ExecutionException, Time requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); chunkProvider.update(); - Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), + Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(JomlUtil.from(chunkPosition))).isEntityRestored(), "Entities must be restored by loading"); final ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); @@ -209,7 +209,7 @@ void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, Execut requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); chunkProvider.update(); - Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), + Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(JomlUtil.from(chunkPosition))).isEntityRestored(), "Entities must be restored by loading"); diff --git a/engine/src/main/java/org/terasology/persistence/StorageManager.java b/engine/src/main/java/org/terasology/persistence/StorageManager.java index 40f2bf74a3c..4d8f2eae94f 100644 --- a/engine/src/main/java/org/terasology/persistence/StorageManager.java +++ b/engine/src/main/java/org/terasology/persistence/StorageManager.java @@ -15,6 +15,7 @@ */ package org.terasology.persistence; +import org.joml.Vector3ic; import org.terasology.math.geom.Vector3i; import org.terasology.network.Client; import org.terasology.world.chunks.Chunk; @@ -50,7 +51,7 @@ public interface StorageManager { * * @param chunkPos */ - ChunkStore loadChunkStore(Vector3i chunkPos); + ChunkStore loadChunkStore(Vector3ic chunkPos); void finishSavingAndShutdown(); diff --git a/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java b/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java index 840282c6ee6..d3b539fc42a 100644 --- a/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java +++ b/engine/src/main/java/org/terasology/persistence/internal/AbstractStorageManager.java @@ -18,17 +18,15 @@ import com.google.common.collect.Lists; import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.internal.EngineEntityManager; import org.terasology.entitySystem.entity.internal.OwnershipHelper; -import org.terasology.joml.geom.AABBf; import org.terasology.joml.geom.AABBfc; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.AABB; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.module.ModuleEnvironment; import org.terasology.network.ClientComponent; import org.terasology.persistence.ChunkStore; @@ -107,7 +105,7 @@ public PlayerStore loadPlayerStore(String playerId) { } @Override - public ChunkStore loadChunkStore(Vector3i chunkPos) { + public ChunkStore loadChunkStore(Vector3ic chunkPos) { byte[] chunkData = loadCompressedChunk(chunkPos); ChunkStore store = null; if (chunkData != null) { @@ -122,13 +120,13 @@ public ChunkStore loadChunkStore(Vector3i chunkPos) { return store; } - protected byte[] loadChunkZip(Vector3i chunkPos) { + protected byte[] loadChunkZip(Vector3ic chunkPos) { byte[] chunkData = null; - Vector3i chunkZipPos = JomlUtil.from(storagePathProvider.getChunkZipPosition(JomlUtil.from(chunkPos))); - Path chunkPath = storagePathProvider.getChunkZipPath(JomlUtil.from(chunkZipPos)); + Vector3i chunkZipPos = storagePathProvider.getChunkZipPosition(chunkPos); + Path chunkPath = storagePathProvider.getChunkZipPath(chunkZipPos); if (Files.isRegularFile(chunkPath)) { try (FileSystem chunkZip = FileSystems.newFileSystem(chunkPath, null)) { - Path targetChunk = chunkZip.getPath(storagePathProvider.getChunkFilename(JomlUtil.from(chunkPos))); + Path targetChunk = chunkZip.getPath(storagePathProvider.getChunkFilename(chunkPos)); if (Files.isRegularFile(targetChunk)) { chunkData = Files.readAllBytes(targetChunk); } @@ -154,11 +152,11 @@ void setStoreChunksInZips(boolean storeChunksInZips) { this.storeChunksInZips = storeChunksInZips; } - protected byte[] loadCompressedChunk(Vector3i chunkPos) { + protected byte[] loadCompressedChunk(Vector3ic chunkPos) { if (isStoreChunksInZips()) { return loadChunkZip(chunkPos); } else { - Path chunkPath = storagePathProvider.getChunkPath(JomlUtil.from(chunkPos)); + Path chunkPath = storagePathProvider.getChunkPath(chunkPos); if (Files.isRegularFile(chunkPath)) { try { return Files.readAllBytes(chunkPath); @@ -191,7 +189,11 @@ protected Collection getEntitiesOfChunk(Chunk chunk) { for (EntityRef entity : getEntityManager().getEntitiesWith(LocationComponent.class)) { if (!entity.getOwner().exists() && !entity.isAlwaysRelevant() && !entity.hasComponent(ClientComponent.class)) { LocationComponent loc = entity.getComponent(LocationComponent.class); - if (loc != null&& !Float.isNaN(loc.getWorldPosition().x)) { + if (loc == null) { + continue; + } + Vector3f pos = loc.getWorldPosition(new Vector3f()); + if (pos.isFinite()) { if (aabb.containsPoint(loc.getWorldPosition(new Vector3f()))) { entitiesToStore.add(entity); } diff --git a/engine/src/main/java/org/terasology/persistence/internal/PlayerStoreBuilder.java b/engine/src/main/java/org/terasology/persistence/internal/PlayerStoreBuilder.java index 5ec4a9e1cc7..e1db0a51203 100644 --- a/engine/src/main/java/org/terasology/persistence/internal/PlayerStoreBuilder.java +++ b/engine/src/main/java/org/terasology/persistence/internal/PlayerStoreBuilder.java @@ -16,6 +16,7 @@ package org.terasology.persistence.internal; import com.google.common.collect.Sets; +import org.joml.Vector3fc; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.internal.EngineEntityManager; import org.terasology.math.geom.Vector3f; @@ -30,26 +31,26 @@ */ class PlayerStoreBuilder { private Long characterEntityId; - private Vector3f relevanceLocation; + private Vector3fc relevanceLocation; private Set storedEntities; - PlayerStoreBuilder(Long characterEntityId, Vector3f relevanceLocation) { + PlayerStoreBuilder(Long characterEntityId, Vector3fc relevanceLocation) { this.characterEntityId = characterEntityId; this.relevanceLocation = relevanceLocation; } public EntityData.PlayerStore build(EngineEntityManager entityManager) { EntityData.PlayerStore.Builder playerEntityStore = EntityData.PlayerStore.newBuilder(); - playerEntityStore.setCharacterPosX(relevanceLocation.x); - playerEntityStore.setCharacterPosY(relevanceLocation.y); - playerEntityStore.setCharacterPosZ(relevanceLocation.z); + playerEntityStore.setCharacterPosX(relevanceLocation.x()); + playerEntityStore.setCharacterPosY(relevanceLocation.y()); + playerEntityStore.setCharacterPosZ(relevanceLocation.z()); playerEntityStore.setHasCharacter(characterEntityId != null); if (characterEntityId != null) { EntityRef character = entityManager.getEntity(characterEntityId); - EntityStorer storer = new EntityStorer(entityManager); - storer.store(character, PlayerStoreInternal.CHARACTER); - storedEntities = storer.getStoredEntities(); - playerEntityStore.setStore(storer.finaliseStore()); + EntityStorer store = new EntityStorer(entityManager); + store.store(character, PlayerStoreInternal.CHARACTER); + storedEntities = store.getStoredEntities(); + playerEntityStore.setStore(store.finaliseStore()); } else { storedEntities = Sets.newHashSet(); } diff --git a/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java b/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java index 4fc61269209..95a0907e95d 100644 --- a/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java +++ b/engine/src/main/java/org/terasology/persistence/internal/ReadWriteStorageManager.java @@ -17,6 +17,9 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.config.Config; @@ -36,8 +39,7 @@ import org.terasology.game.Game; import org.terasology.game.GameManifest; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.JomlUtil; import org.terasology.module.Module; import org.terasology.module.ModuleEnvironment; import org.terasology.monitoring.PerformanceMonitor; @@ -103,8 +105,8 @@ public final class ReadWriteStorageManager extends AbstractStorageManager implem */ private Long nextAutoSave; private boolean saveRequested; - private ConcurrentMap unloadedAndUnsavedChunkMap = Maps.newConcurrentMap(); - private ConcurrentMap unloadedAndSavingChunkMap = Maps.newConcurrentMap(); + private ConcurrentMap unloadedAndUnsavedChunkMap = Maps.newConcurrentMap(); + private ConcurrentMap unloadedAndSavingChunkMap = Maps.newConcurrentMap(); private ConcurrentMap unloadedAndUnsavedPlayerMap = Maps.newConcurrentMap(); private ConcurrentMap unloadedAndSavingPlayerMap = Maps.newConcurrentMap(); @@ -221,22 +223,22 @@ private void addChunksToSaveTransaction(SaveTransactionBuilder saveTransactionBu * ones added in between putAll and clear. By iterating we can make sure that all entries removed * from unloadedAndUnsavedChunkMap get added to unloadedAndSavingChunkMap. */ - Iterator> unsavedEntryIterator = unloadedAndUnsavedChunkMap.entrySet().iterator(); + Iterator> unsavedEntryIterator = unloadedAndUnsavedChunkMap.entrySet().iterator(); while (unsavedEntryIterator.hasNext()) { - Map.Entry entry = unsavedEntryIterator.next(); + Map.Entry entry = unsavedEntryIterator.next(); unloadedAndSavingChunkMap.put(entry.getKey(), entry.getValue()); unsavedEntryIterator.remove(); } chunkProvider.getAllChunks().stream().filter(ManagedChunk::isReady).forEach(chunk -> { // If there is a newer undisposed version of the chunk,we don't need to save the disposed version: - unloadedAndSavingChunkMap.remove(chunk.getPosition()); + unloadedAndSavingChunkMap.remove(chunk.getPosition(new Vector3i())); ChunkImpl chunkImpl = (ChunkImpl) chunk; // this storage manager can only work with ChunkImpls saveTransactionBuilder.addLoadedChunk(chunk.getPosition(), chunkImpl); }); - for (Map.Entry entry : unloadedAndSavingChunkMap.entrySet()) { - saveTransactionBuilder.addUnloadedChunk(entry.getKey(), entry.getValue()); + for (Map.Entry entry : unloadedAndSavingChunkMap.entrySet()) { + saveTransactionBuilder.addUnloadedChunk(JomlUtil.from(entry.getKey()), entry.getValue()); } } @@ -310,7 +312,7 @@ private PlayerStoreBuilder createPlayerStore(Client client, EntityRef character) LocationComponent location = character.getComponent(LocationComponent.class); Vector3f relevanceLocation; if (location != null) { - relevanceLocation = location.getWorldPosition(); + relevanceLocation = location.getWorldPosition(new Vector3f()); } else { relevanceLocation = new Vector3f(); } @@ -327,14 +329,14 @@ private PlayerStoreBuilder createPlayerStore(Client client, EntityRef character) public void deactivateChunk(Chunk chunk) { Collection entitiesOfChunk = getEntitiesOfChunk(chunk); ChunkImpl chunkImpl = (ChunkImpl) chunk; // storage manager only works with ChunkImpl - unloadedAndUnsavedChunkMap.put(chunk.getPosition(), new CompressedChunkBuilder(getEntityManager(), chunkImpl, + unloadedAndUnsavedChunkMap.put(chunk.getPosition(new Vector3i()), new CompressedChunkBuilder(getEntityManager(), chunkImpl, entitiesOfChunk, true)); entitiesOfChunk.forEach(this::deactivateOrDestroyEntityRecursive); } @Override - protected byte[] loadCompressedChunk(Vector3i chunkPos) { + protected byte[] loadCompressedChunk(Vector3ic chunkPos) { CompressedChunkBuilder disposedUnsavedChunk = unloadedAndUnsavedChunkMap.get(chunkPos); if (disposedUnsavedChunk != null) { return disposedUnsavedChunk.buildEncodedChunk(); diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 45c41816edb..90d5698a5f5 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -127,7 +127,7 @@ protected Future createOrLoadChunk(Vector3i chunkPos) { return loadingPipeline.invokeGeneratorTask( JomlUtil.from(chunkPos), () -> { - ChunkStore chunkStore = storageManager.loadChunkStore(chunkPos); + ChunkStore chunkStore = storageManager.loadChunkStore(JomlUtil.from(chunkPos)); Chunk chunk; EntityBufferImpl buffer = new EntityBufferImpl(); if (chunkStore == null) { @@ -194,7 +194,7 @@ private void processReadyChunk(final Chunk chunk) { chunk.markReady(); //TODO, it is not clear if the activate/addedBlocks event logic is correct. //See https://github.com/MovingBlocks/Terasology/issues/3244 - ChunkStore store = this.storageManager.loadChunkStore(chunk.getPosition()); + ChunkStore store = this.storageManager.loadChunkStore(chunk.getPosition(new org.joml.Vector3i())); TShortObjectMap mappings = createBatchBlockEventMappings(chunk); if (store != null) { store.restoreEntities(); From d8bb407704d710f2706dace0d01f6e0522089604 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 29 Jan 2021 04:09:37 -0800 Subject: [PATCH 156/259] feat(JOML): migrate aabb for SkeletonRenderer (#4431) Co-authored-by: Tobias Nett --- .../headless/assets/HeadlessSkeletalMesh.java | 4 ++-- .../rendering/assets/animation/MeshAnimation.java | 4 ++-- .../assets/animation/MeshAnimationData.java | 8 ++++---- .../assets/animation/MeshAnimationImpl.java | 3 ++- .../rendering/assets/skeletalmesh/SkeletalMesh.java | 4 ++-- .../assets/skeletalmesh/SkeletalMeshData.java | 8 ++++---- .../skeletalmesh/SkeletalMeshDataBuilder.java | 5 ++--- .../rendering/gltf/GLTFAnimationFormat.java | 3 ++- .../rendering/logic/SkeletonRenderer.java | 13 ++++++------- .../rendering/opengl/OpenGLSkeletalMesh.java | 4 ++-- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessSkeletalMesh.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessSkeletalMesh.java index 819f7191656..0f86e715200 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessSkeletalMesh.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/assets/HeadlessSkeletalMesh.java @@ -18,7 +18,7 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import org.terasology.rendering.assets.skeletalmesh.Bone; import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; import org.terasology.rendering.assets.skeletalmesh.SkeletalMeshData; @@ -61,7 +61,7 @@ public Bone getBone(String boneName) { } @Override - public AABB getStaticAabb() { + public AABBf getStaticAabb() { return data.getStaticAABB(); } } diff --git a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimation.java b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimation.java index b6f258f6d9a..972af1fa901 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimation.java +++ b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimation.java @@ -19,7 +19,7 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; /** @@ -42,5 +42,5 @@ protected MeshAnimation(ResourceUrn urn, AssetType assetTy public abstract float getTimePerFrame(); - public abstract AABB getAabb(); + public abstract AABBf getAabb(); } diff --git a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationData.java b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationData.java index 26b77866641..58235993870 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationData.java +++ b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationData.java @@ -19,7 +19,7 @@ import gnu.trove.list.TIntList; import gnu.trove.list.array.TIntArrayList; import org.terasology.assets.AssetData; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import java.util.List; @@ -33,7 +33,7 @@ public class MeshAnimationData implements AssetData { private TIntList boneParent; private List frames; private float timePerFrame; - private AABB aabb; + private AABBf aabb; /** * @param boneNames The names of the bones this animation expects @@ -43,7 +43,7 @@ public class MeshAnimationData implements AssetData { * @param timePerFrame */ public MeshAnimationData(List boneNames, TIntList boneParents, List frames, - float timePerFrame, AABB aabb) { + float timePerFrame, AABBf aabb) { if (boneNames.size() != boneParents.size()) { throw new IllegalArgumentException("Bone names and boneParent indices must align"); } @@ -70,7 +70,7 @@ public float getTimePerFrame() { return timePerFrame; } - public AABB getAabb() { + public AABBf getAabb() { return aabb; } } diff --git a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationImpl.java b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationImpl.java index 45c8bb46c81..796c5e2af33 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationImpl.java +++ b/engine/src/main/java/org/terasology/rendering/assets/animation/MeshAnimationImpl.java @@ -18,6 +18,7 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; +import org.terasology.joml.geom.AABBf; import org.terasology.math.AABB; import org.terasology.rendering.assets.skeletalmesh.Bone; import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; @@ -75,7 +76,7 @@ public float getTimePerFrame() { } @Override - public AABB getAabb() { + public AABBf getAabb() { return data.getAabb(); } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMesh.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMesh.java index 5288a1e9d87..af2e65e9540 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMesh.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMesh.java @@ -19,7 +19,7 @@ import org.terasology.assets.Asset; import org.terasology.assets.AssetType; import org.terasology.assets.ResourceUrn; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import java.util.Collection; @@ -41,5 +41,5 @@ protected SkeletalMesh(ResourceUrn urn, AssetType assetType * * @return the boundings of the mesh when it its not being animated. */ - public abstract AABB getStaticAabb(); + public abstract AABBf getStaticAabb(); } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java index 44d398d5f57..a6e1c9b5e6e 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshData.java @@ -24,7 +24,7 @@ import org.joml.Vector2f; import org.joml.Vector3f; import org.terasology.assets.AssetData; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import java.util.Arrays; import java.util.Collection; @@ -44,10 +44,10 @@ public class SkeletalMeshData implements AssetData { private List normals; private List weights = Lists.newArrayList(); private TIntList indices = new TIntArrayList(); - private AABB staticAABB; + private AABBf staticAABB; public SkeletalMeshData(List bones, List vertices, List normals, - List weights, List uvs, TIntList indices, AABB staticAABB) { + List weights, List uvs, TIntList indices, AABBf staticAABB) { for (Bone bone : bones) { boneLookup.put(bone.getName(), bone); if (bone.getParent() == null) { @@ -180,7 +180,7 @@ public List getUVs() { /** * @return A axis-aligned bounding box that surrounds the skeletal mesh given its default pose. */ - public AABB getStaticAABB() { + public AABBf getStaticAABB() { return staticAABB; } diff --git a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java index f54067f0d5b..f73787d8e07 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/skeletalmesh/SkeletalMeshDataBuilder.java @@ -20,8 +20,7 @@ import gnu.trove.list.array.TIntArrayList; import org.joml.Vector2f; import org.joml.Vector3f; -import org.terasology.math.AABB; -import org.terasology.math.JomlUtil; +import org.terasology.joml.geom.AABBf; import org.terasology.rendering.assets.mesh.MeshBuilder; import org.terasology.rendering.assets.mesh.MeshData; @@ -124,7 +123,7 @@ public SkeletalMeshData build() { } else if (rootBones > 1) { throw new IllegalStateException("Cannot create a skeleton with multiple root bones"); } - AABB staticAabb = AABB.createMinMax(JomlUtil.from(minOfAABB), JomlUtil.from(maxOfAABB)); + AABBf staticAabb = new AABBf(minOfAABB, maxOfAABB); return new SkeletalMeshData(bones, vertices, normals, weights, uvs, indices, staticAabb); } diff --git a/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java b/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java index dd4f6770fae..7cc7d29c0c7 100644 --- a/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java +++ b/engine/src/main/java/org/terasology/rendering/gltf/GLTFAnimationFormat.java @@ -29,6 +29,7 @@ import org.terasology.assets.format.AssetDataFile; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.annotations.RegisterAssetFileFormat; +import org.terasology.joml.geom.AABBf; import org.terasology.math.AABB; import org.terasology.rendering.assets.animation.MeshAnimationBundleData; import org.terasology.rendering.assets.animation.MeshAnimationData; @@ -159,7 +160,7 @@ private MeshAnimationData loadAnimation(GLTF gltf, GLTFAnimation animation, List frames.add(frame); } - return new MeshAnimationData(boneNames, boneParents, frames, TIME_PER_FRAME, AABB.createEmpty()); + return new MeshAnimationData(boneNames, boneParents, frames, TIME_PER_FRAME, new AABBf(0, 0, 0)); } private TFloatList getFloats(GLTF gltf, List loadedBuffers, int accessorIndex) throws IOException { diff --git a/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java index 11d48b6ee5d..b09430f2bf4 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/SkeletonRenderer.java @@ -23,9 +23,9 @@ import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.RenderSystem; import org.terasology.entitySystem.systems.UpdateSubscriberSystem; +import org.terasology.joml.geom.AABBf; import org.terasology.logic.location.Location; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.AABB; import org.terasology.math.JomlUtil; import org.terasology.registry.In; import org.terasology.rendering.assets.animation.MeshAnimation; @@ -40,7 +40,6 @@ import java.util.Arrays; import java.util.List; import java.util.Random; -import java.util.stream.Collectors; import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; import static org.lwjgl.opengl.GL11.glBegin; @@ -227,7 +226,7 @@ public void renderOpaque() { if (skeletalMesh.mesh == null || skeletalMesh.material == null || skeletalMesh.boneEntities == null || !skeletalMesh.material.isRenderable()) { continue; } - AABB aabb; + AABBf aabb; MeshAnimation animation = skeletalMesh.animation; if (animation != null) { aabb = animation.getAabb(); @@ -240,15 +239,15 @@ public void renderOpaque() { location.getWorldPosition(worldPos); float worldScale = location.getWorldScale(); - aabb = aabb.transform(JomlUtil.from(worldRot), JomlUtil.from(worldPos), worldScale); + aabb = aabb.transform(new Matrix4f().translationRotateScale(worldPos, worldRot, worldScale), new AABBf()); //Scale bounding box for skeletalMesh. Vector3f scale = skeletalMesh.scale; - Vector3f aabbCenter = JomlUtil.from(aabb.getCenter()); - Vector3f scaledExtents = JomlUtil.from(aabb.getExtents().mul(scale.x(), scale.y(), scale.z())); - aabb = AABB.createCenterExtent(JomlUtil.from(aabbCenter), JomlUtil.from(scaledExtents)); + Vector3f aabbCenter = aabb.center(new Vector3f()); + Vector3f scaledExtents = aabb.extent(new Vector3f()).mul(scale.x(), scale.y(), scale.z()); + aabb = new AABBf(aabbCenter, aabbCenter).expand(scaledExtents); if (!worldRenderer.getActiveCamera().hasInSight(aabb)) { continue; diff --git a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java index c04ccd5cc28..3da65da2945 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/OpenGLSkeletalMesh.java @@ -29,7 +29,7 @@ import org.terasology.engine.GameThread; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.engine.subsystem.lwjgl.LwjglGraphicsProcessing; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBf; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.skeletalmesh.Bone; import org.terasology.rendering.assets.skeletalmesh.SkeletalMesh; @@ -192,7 +192,7 @@ public Bone getBone(String boneName) { } @Override - public AABB getStaticAabb() { + public AABBf getStaticAabb() { return data.getStaticAABB(); } From 791c4c0b7de36d6f9b3faf0416879d99ebbb0ec4 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 29 Jan 2021 05:06:55 -0800 Subject: [PATCH 157/259] feat(JOML): migrate RegionOutlineRenderer (#4434) --- .../logic/RegionOutlineComponent.java | 4 +- .../logic/RegionOutlineRenderer.java | 57 +++++++++---------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineComponent.java b/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineComponent.java index 7970ab94811..2ac12ad7953 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineComponent.java +++ b/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineComponent.java @@ -15,7 +15,7 @@ */ package org.terasology.rendering.logic; -import org.terasology.math.geom.Vector3i; +import org.joml.Vector3i; import org.terasology.nui.Color; /** @@ -24,5 +24,5 @@ public class RegionOutlineComponent implements VisualComponent { public Vector3i corner1; public Vector3i corner2; - public Color color = Color.WHITE; + public Color color = new Color(Color.white); } diff --git a/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineRenderer.java b/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineRenderer.java index 1c2de3f1582..3410d8b73af 100644 --- a/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/logic/RegionOutlineRenderer.java @@ -34,10 +34,11 @@ import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; import org.terasology.entitySystem.systems.RenderSystem; -import org.terasology.math.Region3i; +import org.terasology.joml.geom.AABBf; import org.terasology.registry.In; import org.terasology.rendering.assets.material.Material; import org.terasology.rendering.world.WorldRenderer; +import org.terasology.world.block.BlockRegion; import java.nio.FloatBuffer; import java.util.Map; @@ -131,72 +132,70 @@ private void drawRegionOutline(RegionOutlineComponent regionComponent) { return; } - Region3i region = Region3i.createBounded(regionComponent.corner1, regionComponent.corner2); - Vector3f min = new Vector3f(region.minX() - 0.5f, region.minY() - 0.5f, region.minZ() - 0.5f); - Vector3f max = new Vector3f(region.maxX() + 0.5f, region.maxY() + 0.5f, region.maxZ() + 0.5f); - + BlockRegion region = new BlockRegion(regionComponent.corner1).union(regionComponent.corner2); + AABBf bounds = region.getBounds(new AABBf()); // 4 lines along x axis: glBegin(GL11.GL_LINES); - glVertex3f(min.x(), min.y(), min.z()); - glVertex3f(max.x(), min.y(), min.z()); + glVertex3f(bounds.minX, bounds.minY, bounds.minZ); + glVertex3f(bounds.maxX, bounds.minY, bounds.minZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(min.x(), max.y(), min.z()); - glVertex3f(max.x(), max.y(), min.z()); + glVertex3f(bounds.minX, bounds.maxY, bounds.minZ); + glVertex3f(bounds.maxX, bounds.maxY, bounds.minZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(min.x(), min.y(), max.z()); - glVertex3f(max.x(), min.y(), max.z()); + glVertex3f(bounds.minX, bounds.minY, bounds.maxZ); + glVertex3f(bounds.maxX, bounds.minY, bounds.maxZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(min.x(), max.y(), max.z()); - glVertex3f(max.x(), max.y(), max.z()); + glVertex3f(bounds.minX, bounds.maxY, bounds.maxZ); + glVertex3f(bounds.maxX, bounds.maxY, bounds.maxZ); glEnd(); // 4 lines along y axis glBegin(GL11.GL_LINES); - glVertex3f(min.x(), min.y(), min.z()); - glVertex3f(min.x(), max.y(), min.z()); + glVertex3f(bounds.minX, bounds.minY, bounds.minZ); + glVertex3f(bounds.minX, bounds.maxY, bounds.minZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(max.x(), min.y(), min.z()); - glVertex3f(max.x(), max.y(), min.z()); + glVertex3f(bounds.maxX, bounds.minY, bounds.minZ); + glVertex3f(bounds.maxX, bounds.maxY, bounds.minZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(min.x(), min.y(), max.z()); - glVertex3f(min.x(), max.y(), max.z()); + glVertex3f(bounds.minX, bounds.minY, bounds.maxZ); + glVertex3f(bounds.minX, bounds.maxY, bounds.maxZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(max.x(), min.y(), max.z()); - glVertex3f(max.x(), max.y(), max.z()); + glVertex3f(bounds.maxX, bounds.minY, bounds.maxZ); + glVertex3f(bounds.maxX, bounds.maxY, bounds.maxZ); glEnd(); // 4 lines along z axis: glBegin(GL11.GL_LINES); - glVertex3f(min.x(), min.y(), min.z()); - glVertex3f(min.x(), min.y(), max.z()); + glVertex3f(bounds.minX, bounds.minY, bounds.minZ); + glVertex3f(bounds.minX, bounds.minY, bounds.maxZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(max.x(), min.y(), min.z()); - glVertex3f(max.x(), min.y(), max.z()); + glVertex3f(bounds.maxX, bounds.minY, bounds.minZ); + glVertex3f(bounds.maxX, bounds.minY, bounds.maxZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(min.x(), max.y(), min.z()); - glVertex3f(min.x(), max.y(), max.z()); + glVertex3f(bounds.minX, bounds.maxY, bounds.minZ); + glVertex3f(bounds.minX, bounds.maxY, bounds.maxZ); glEnd(); glBegin(GL11.GL_LINES); - glVertex3f(max.x(), max.y(), min.z()); - glVertex3f(max.x(), max.y(), max.z()); + glVertex3f(bounds.maxX, bounds.maxY, bounds.minZ); + glVertex3f(bounds.maxX, bounds.maxY, bounds.maxZ); glEnd(); } From fdeb02483fbe0a03ede0d7e3487ceec9bda5ab98 Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Fri, 29 Jan 2021 16:42:09 +0300 Subject: [PATCH 158/259] fix(joml): Fix always growing relevance region (#4436) --- .../world/chunks/localChunkProvider/RelevanceSystem.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java index 5a52abc3558..b82f5c2f93e 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks.localChunkProvider; @@ -17,6 +17,7 @@ import org.terasology.monitoring.PerformanceMonitor; import org.terasology.world.RelevanceRegionComponent; import org.terasology.world.WorldComponent; +import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkRegionListener; import org.terasology.world.chunks.event.BeforeChunkUnload; @@ -195,7 +196,7 @@ public void addRelevanceEntity(EntityRef entity, Vector3ic distance, ChunkRegion */ public boolean isChunkInRegions(Vector3ic pos) { for (ChunkRelevanceRegion region : regions.values()) { - if (region.getCurrentRegion().expand(UNLOAD_LEEWAY).contains(pos)) { + if (new BlockRegion(region.getCurrentRegion()).expand(UNLOAD_LEEWAY).contains(pos)) { return true; } } From ad463efdf74bfbfa987f72728aa5c7c5765c3fe7 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Fri, 29 Jan 2021 16:43:27 +0100 Subject: [PATCH 159/259] chore(JOML): remove unused imports (Region3i) and update copyright (#4437) --- .../facets/BaseBooleanFacetTest.java | 1 - .../facets/BaseObjectFacetTest.java | 1 - .../selection/ApplyBlockSelectionEvent.java | 20 +++--------------- .../selection/MovableSelectionEndEvent.java | 20 +++--------------- .../terasology/world/chunks/CoreChunk.java | 21 ++----------------- .../chunks/internal/ChunkRelevanceRegion.java | 20 ++---------------- .../world/generation/RegionImpl.java | 18 ++-------------- .../terasology/world/generation/World.java | 18 ++-------------- .../world/generation/WorldImpl.java | 18 ++-------------- 9 files changed, 16 insertions(+), 121 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java index 4f06517a070..a49e7cefb32 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseBooleanFacetTest.java @@ -16,7 +16,6 @@ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseBooleanFieldFacet3D; diff --git a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java index 7c903fcf13d..87782c43f04 100644 --- a/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generation/facets/BaseObjectFacetTest.java @@ -16,7 +16,6 @@ package org.terasology.world.generation.facets; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.generation.Border3D; import org.terasology.world.generation.facets.base.BaseObjectFacet3D; diff --git a/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java b/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java index cf16dad9b41..22f40b75307 100644 --- a/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java +++ b/engine/src/main/java/org/terasology/logic/selection/ApplyBlockSelectionEvent.java @@ -1,24 +1,10 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.selection; -import org.terasology.module.sandbox.API; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.Event; -import org.terasology.math.Region3i; +import org.terasology.module.sandbox.API; import org.terasology.world.block.BlockRegion; /** diff --git a/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java b/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java index 6e8b41a96aa..958f5f894be 100644 --- a/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java +++ b/engine/src/main/java/org/terasology/logic/selection/MovableSelectionEndEvent.java @@ -1,23 +1,9 @@ -/* - * Copyright 2019 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.selection; -import org.terasology.module.sandbox.API; import org.terasology.entitySystem.event.Event; -import org.terasology.math.Region3i; +import org.terasology.module.sandbox.API; import org.terasology.world.block.BlockRegion; /** diff --git a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java index 9bdd8213549..74ad0a763e4 100644 --- a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java @@ -1,25 +1,8 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks; -import org.joml.Vector3fc; import org.joml.Vector3ic; -import org.terasology.audio.AudioEndListener; -import org.terasology.audio.StaticSound; -import org.terasology.math.Region3i; import org.terasology.math.geom.BaseVector3i; import org.terasology.math.geom.Vector3i; import org.terasology.module.sandbox.API; diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java index 026ade11375..afd434bfee5 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkRelevanceRegion.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks.internal; @@ -23,9 +10,6 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.ChunkMath; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkRegionListener; diff --git a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java index 5d0c275ba7d..94188e7b44f 100644 --- a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java @@ -1,23 +1,9 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.generation; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; -import org.terasology.math.Region3i; import org.terasology.utilities.collection.TypeMap; import org.terasology.world.block.BlockRegion; diff --git a/engine/src/main/java/org/terasology/world/generation/World.java b/engine/src/main/java/org/terasology/world/generation/World.java index 42756f8070b..61e78acf748 100644 --- a/engine/src/main/java/org/terasology/world/generation/World.java +++ b/engine/src/main/java/org/terasology/world/generation/World.java @@ -1,21 +1,7 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.generation; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.CoreChunk; diff --git a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java index ebdbfb52215..3ad2055bb8c 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java @@ -1,23 +1,9 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.generation; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; -import org.terasology.math.Region3i; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.CoreChunk; From bda6a37c7dd7e73305035cec8d35007dd4d162d2 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 29 Jan 2021 09:32:30 -0800 Subject: [PATCH 160/259] feat(JOML): migrate assertions with joml-ext (#4432) requires PR: https://github.com/MovingBlocks/joml-ext/pull/13 --- engine-tests/build.gradle | 2 + .../logic/location/LocationComponentTest.java | 40 ++++++++++--------- .../org/terasology/math/RotationTest.java | 14 +++---- .../serializers/VectorTypeSerializerTest.java | 33 ++++++++------- .../event/VectorEventSerializer.java | 15 +++---- 5 files changed, 56 insertions(+), 48 deletions(-) diff --git a/engine-tests/build.gradle b/engine-tests/build.gradle index 084c36955e6..246d6475810 100644 --- a/engine-tests/build.gradle +++ b/engine-tests/build.gradle @@ -62,6 +62,8 @@ dependencies { implementation("org.junit.jupiter:junit-jupiter-params:5.5.2") implementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.2.0' + implementation("org.terasology.joml-ext:joml-test:1.0.0-SNAPSHOT") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.5.2") implementation group: 'junit', name: 'junit', version: '4.12' diff --git a/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java b/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java index 1145c76d86b..6cc673a30d4 100644 --- a/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java +++ b/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java @@ -24,11 +24,13 @@ import org.terasology.entitySystem.entity.lifecycleEvents.BeforeRemoveComponent; import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; -import org.terasology.testUtil.TeraAssert; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.terasology.joml.test.VectorAssert.assertEquals; +import static org.terasology.joml.test.QuaternionAssert.assertEquals; + /** */ @@ -71,7 +73,7 @@ public void testSetLocalPosition() { @Test public void testSetLocalRotation() { loc.setLocalRotation(yawRotation); - TeraAssert.assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); + assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); } @Test @@ -93,7 +95,7 @@ public void testParentRotatesWorldLocation() { LocationComponent parent = giveParent(); loc.setLocalPosition(pos1); parent.setLocalRotation(yawRotation); - TeraAssert.assertEquals(new Vector3f(pos1.z, pos1.y, -pos1.x), loc.getWorldPosition(new Vector3f()), 0.00001f); + assertEquals(new Vector3f(pos1.z, pos1.y, -pos1.x), loc.getWorldPosition(new Vector3f()), 0.00001f); } @Test @@ -113,7 +115,7 @@ public void testScaleRotateAndOffsetCombineCorrectlyForWorldPosition() { parent.setLocalPosition(pos2); parent.setLocalRotation(yawRotation); - TeraAssert.assertEquals(new Vector3f(8, 7, 2), loc.getWorldPosition(new Vector3f()), 0.00001f); + assertEquals(new Vector3f(8, 7, 2), loc.getWorldPosition(new Vector3f()), 0.00001f); } @Test @@ -127,7 +129,7 @@ public void testWorldRotationCombinedWithParent() { LocationComponent parent = giveParent(); loc.setLocalRotation(pitchRotation); parent.setLocalRotation(yawRotation); - TeraAssert.assertEquals(yawPitch, loc.getWorldRotation(new Quaternionf()), 0.0001f); + assertEquals(yawPitch, loc.getWorldRotation(new Quaternionf()), 0.0001f); } @Test @@ -147,7 +149,7 @@ public void testWorldScaleStacksWithParent() { @Test public void testSetWorldPositionWorksWithNoParent() { loc.setWorldPosition(pos1); - TeraAssert.assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.0001f); + assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.0001f); } @Test @@ -155,7 +157,7 @@ public void testSetWorldPositionWorksWithOffsetParent() { LocationComponent parent = giveParent(); parent.setLocalPosition(pos1); loc.setWorldPosition(pos1plus2); - TeraAssert.assertEquals(pos2, JomlUtil.from(loc.getLocalPosition()), 0.0001f); + assertEquals(pos2, JomlUtil.from(loc.getLocalPosition()), 0.0001f); assertEquals(pos1plus2, loc.getWorldPosition(new Vector3f())); } @@ -164,7 +166,7 @@ public void testSetWorldPositionWorksWithScaledParent() { LocationComponent parent = giveParent(); parent.setLocalScale(2.0f); loc.setWorldPosition(pos1); - TeraAssert.assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.0001f); + assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.0001f); } @Test @@ -172,7 +174,7 @@ public void testSetWorldPositionWorksWithRotatedParent() { LocationComponent parent = giveParent(); parent.setLocalRotation(yawRotation); loc.setWorldPosition(pos1); - TeraAssert.assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.000001f); } @Test @@ -189,13 +191,13 @@ public void testSetWorldPositionWorksWithNestedRotatedParent() { Location.attachChild(firstEntity, secondEntity); second.setLocalPosition(new Vector3f(1, 0, 0)); first.setLocalRotation(yawRotation); - TeraAssert.assertEquals(new Vector3f(0, 0, -1), second.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(0, 0, -1), second.getWorldPosition(new Vector3f()), 0.000001f); Location.attachChild(secondEntity, thirdEntity); second.setLocalRotation(pitchRotation); third.setLocalPosition(new Vector3f(0, 0, 0)); - TeraAssert.assertEquals(new Vector3f(0, 0, -1), third.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(0, 0, -1), third.getWorldPosition(new Vector3f()), 0.000001f); third.setLocalPosition(new Vector3f(0, 0, 1)); - TeraAssert.assertEquals(new Vector3f(0.5f * (float) Math.sqrt(2), -0.5f * (float) Math.sqrt(2), -1), third.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(0.5f * (float) Math.sqrt(2), -0.5f * (float) Math.sqrt(2), -1), third.getWorldPosition(new Vector3f()), 0.000001f); } @@ -206,7 +208,7 @@ public void testSetWorldPositionWorksWithComplexParent() { parent.setLocalScale(2.0f); parent.setLocalPosition(pos2); loc.setWorldPosition(pos1); - TeraAssert.assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(pos1, loc.getWorldPosition(new Vector3f()), 0.000001f); } @Test @@ -227,8 +229,8 @@ public void testSetWorldScaleWorksWithScaledParent() { @Test public void testSetWorldRotationWorksWithNoParent() { loc.setWorldRotation(yawRotation); - TeraAssert.assertEquals(yawRotation, loc.getWorldRotation(new Quaternionf()), 0.0001f); - TeraAssert.assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); + assertEquals(yawRotation, loc.getWorldRotation(new Quaternionf()), 0.0001f); + assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); } @Test @@ -236,7 +238,7 @@ public void testSetWorldRotationWithRotatedParent() { LocationComponent parent = giveParent(); parent.setLocalRotation(yawRotation); loc.setWorldRotation(yawPitch); - TeraAssert.assertEquals(yawPitch, loc.getWorldRotation(new Quaternionf()), 0.0001f); + assertEquals(yawPitch, loc.getWorldRotation(new Quaternionf()), 0.0001f); } @Test @@ -248,7 +250,7 @@ public void testPositionMaintainedWhenAttachedToParent() { loc.setWorldPosition(new Vector3f(2, 0, 0)); Location.attachChild(parentEntity, entity); - TeraAssert.assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); } @Test @@ -261,7 +263,7 @@ public void testPositionMaintainedWhenRemovedFromParent() { Location.attachChild(parentEntity, entity); Location.removeChild(parentEntity, entity); - TeraAssert.assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); } @Test @@ -277,7 +279,7 @@ public void testPositionMaintainedWhenParentDestroyed() { when(parentEntity.getComponent(LocationComponent.class)).thenReturn(null); when(parentEntity.exists()).thenReturn(false); - TeraAssert.assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); + assertEquals(new Vector3f(2, 0, 0), loc.getWorldPosition(new Vector3f()), 0.000001f); } diff --git a/engine-tests/src/test/java/org/terasology/math/RotationTest.java b/engine-tests/src/test/java/org/terasology/math/RotationTest.java index 849c1cab86f..21bbf7f1ce6 100644 --- a/engine-tests/src/test/java/org/terasology/math/RotationTest.java +++ b/engine-tests/src/test/java/org/terasology/math/RotationTest.java @@ -20,9 +20,9 @@ import org.junit.jupiter.api.Test; import org.terasology.math.geom.Quat4f; import org.terasology.math.geom.Vector3f; -import org.terasology.testUtil.TeraAssert; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.terasology.joml.test.QuaternionAssert.assertEquals; /** */ @@ -46,14 +46,14 @@ public void testRotateSideYaw() { @Test public void testOrientation() { - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(90.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_90).orientation(),0.001f); - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(180.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(90.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_90).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(180.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_180).orientation(),0.001f); - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(0,90.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_90).orientation(),0.001f); - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(0,180.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0,90.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_90).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0,180.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_180).orientation(),0.001f); - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(0,0,90.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_90).orientation(),0.001f); - TeraAssert.assertEquals(new Quaternionf().rotationYXZ(0,0,180.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0,0,90.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_90).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0,0,180.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_180).orientation(),0.001f); } @Test diff --git a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java index fcfc9c8254c..b731d4c514f 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java @@ -17,6 +17,9 @@ import org.terasology.reflection.TypeInfo; import org.terasology.testUtil.TeraAssert; +import static org.terasology.joml.test.VectorAssert.assertEquals; + + import java.io.IOException; public class VectorTypeSerializerTest extends ModuleEnvironmentTest { @@ -66,9 +69,9 @@ public void testSerializationConstant() throws IOException { TestObject2 o = gsonSerializer.fromJson(data, new TypeInfo() { }); - TeraAssert.assertEquals(o.v1, new org.joml.Vector3f(1.0f, 2.0f, 3.0f), .00001f); - TeraAssert.assertEquals(o.v2, new org.joml.Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); - TeraAssert.assertEquals(o.v3, new org.joml.Vector2f(1.0f, 2.0f), .00001f); + assertEquals(o.v1, new org.joml.Vector3f(1.0f, 2.0f, 3.0f), .00001f); + assertEquals(o.v2, new org.joml.Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); + assertEquals(o.v3, new org.joml.Vector2f(1.0f, 2.0f), .00001f); } @Test @@ -87,9 +90,9 @@ public void testJsonSerializeRemapped() throws IOException { TestObject1 o = gsonSerializer.fromJson(data, new TypeInfo() { }); - TeraAssert.assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); + assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } @@ -109,9 +112,9 @@ public void testProtobufSerializeRemapped() throws IOException { TestObject1 o = protobufSerializer.fromBytes(data, new TypeInfo() { }); - TeraAssert.assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); + assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } @@ -135,9 +138,9 @@ public void testJsonSerialize() throws IOException { TeraAssert.assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); TeraAssert.assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - TeraAssert.assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); + assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } @Test @@ -160,9 +163,9 @@ public void testProtobufSerialize() throws IOException { TeraAssert.assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); TeraAssert.assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - TeraAssert.assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); + assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } } diff --git a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java index 6d917b475e0..e4733a889b9 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java +++ b/engine-tests/src/test/java/org/terasology/persistence/typeHandling/event/VectorEventSerializer.java @@ -28,7 +28,8 @@ import org.terasology.reflection.reflect.ReflectionReflectFactory; import org.terasology.registry.CoreRegistry; import org.terasology.testUtil.ModuleManagerFactory; -import org.terasology.testUtil.TeraAssert; + +import static org.terasology.joml.test.VectorAssert.assertEquals; import java.io.IOException; import java.util.HashMap; @@ -105,12 +106,12 @@ public void testEventSerializationConstant() throws IOException { EntityData.Event ev = serializer.serialize(a); Event dev = serializer.deserialize(ev); assumeTrue(dev instanceof Vector3fTestEvent); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v1, new Vector3f(1.0f, 2.0f, 3.0f), .00001f); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v2, new Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v3, new Vector2f(1.0f, 2.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v1, new Vector3f(1.0f, 2.0f, 3.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v2, new Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v3, new Vector2f(1.0f, 2.0f), .00001f); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v1c, new Vector3f(1.0f, 1.0f, 1.0f), .00001f); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v2c, new Vector4f(1.0f, 1.0f, 2.0f, 2.0f), .00001f); - TeraAssert.assertEquals(((Vector3fTestEvent) dev).v3c, new Vector2f(1.0f, 1.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v1c, new Vector3f(1.0f, 1.0f, 1.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v2c, new Vector4f(1.0f, 1.0f, 2.0f, 2.0f), .00001f); + assertEquals(((Vector3fTestEvent) dev).v3c, new Vector2f(1.0f, 1.0f), .00001f); } } From 14565ece2112a361a7df21078b06a553321b6d26 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 14:04:23 -0800 Subject: [PATCH 161/259] chore (build): remove unused variables (post-merge clean-up) --- engine/build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index fb72fcae82d..5a60b086bdb 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -29,8 +29,6 @@ ext { // Stuff for our automatic version file setup startDateTimeString = dateTimeFormat.format(new Date()) - versionInfoFileDir = new File(buildDir, 'classes/org/terasology/version') - versionInfoFile = new File(versionInfoFileDir, 'versionInfo.properties') versionBase = new File(templatesDir, "version.txt").text.trim() displayVersion = versionBase } From d476cd6232b45dc0dab5014fa382697edb8188d4 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 16:50:47 -0800 Subject: [PATCH 162/259] fix (build): merge clean-up --- engine/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/engine/build.gradle b/engine/build.gradle index 5a60b086bdb..4f8a6dbb089 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -227,7 +227,6 @@ def createVersionInfoFile = tasks.register("createVersionInfoFile", WritePropert buildTag: env.BUILD_TAG, buildUrl: env.BUILD_URL, jobName: env.JOB_NAME, - gitBranch: convertGitBranch(env.GIT_BRANCH), gitCommit: env.GIT_COMMIT, displayVersion: displayVersion, engineVersion: version From 6b7694a7085bbcf73eb9900bdb20093ea89fd79d Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 16:57:07 -0800 Subject: [PATCH 163/259] =?UTF-8?q?chore=20(build):=20gradle=206.7=20?= =?UTF-8?q?=E2=86=92=206.8.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 14e30f7416a..1c4bcc29e17 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From b23dc19c6ee6c309fc2c27e3a316e8372623f240 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 17:01:53 -0800 Subject: [PATCH 164/259] fix (build): jar.version property deprecated by gradle and was probably accidental in the first place --- engine/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/build.gradle b/engine/build.gradle index a6449c7ba9f..eea12431d8e 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -165,7 +165,7 @@ jar { def manifestClasspath = "$subDirLibs/" + configurations."${sourceSets.main.runtimeClasspathConfigurationName}".collect { it.getName() }.join(" $subDirLibs/") - attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology", "Implementation-Version": displayVersion + ", engine v" + version + " , build number " + env.BUILD_NUMBER) + attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology", "Implementation-Version": displayVersion + ", engine v" + project.version + " , build number " + env.BUILD_NUMBER) } } } From 73888474d0a28a36ef63d19b1711d381b328e19e Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 20:27:02 -0800 Subject: [PATCH 165/259] test(build): add testDistForLauncher and testDistZip Some checks to make sure files end up where they are expected. --- buildSrc/build.gradle.kts | 4 +- .../main/kotlin/terasology-dist.gradle.kts | 43 +++++++++++++++++++ facades/PC/build.gradle.kts | 40 ++++++++++++++++- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 buildSrc/src/main/kotlin/terasology-dist.gradle.kts diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8c014a97deb..b42130d4cba 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 import java.net.URI @@ -25,4 +25,6 @@ dependencies { // for inspecting modules implementation("org.terasology:gestalt-module:5.1.5") + + implementation(kotlin("test")) } diff --git a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts new file mode 100644 index 00000000000..670f15980ed --- /dev/null +++ b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts @@ -0,0 +1,43 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +@Suppress("UnstableApiUsage") +open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : DefaultTask() { + @InputFile + val zipFile: RegularFileProperty = objects.fileProperty() + + @get:Internal + val tree by lazy { + zipFile.finalizeValue() + project.zipTree(zipFile) + } + + init { + group = "verification" + } + + @TaskAction + fun checkZip() { + zipFile.finalizeValueOnRead() + } + + fun fromTask(taskProvider: Provider) { + // FIXME: is it right to use .get here? + // https://discuss.gradle.org/t/un-nesting-provider-provider/38904 + val fileProvider = taskProvider.map { it.archiveFile }.get() + zipFile.set(fileProvider) + } + + fun assertEquals(expected: Any, actual: Any, message: String? = null) = + kotlin.test.assertEquals(expected, actual, message) + + fun fail(message: String): Nothing = kotlin.test.fail(message) + + fun assertContainsPath(expected: String) { + assertEquals(1, tree.matching { + include(expected) + }.count(), "Matches for $expected") + } +} + + diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index f42323186b2..ec8b29a9999 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -3,6 +3,7 @@ // The PC facade is responsible for the primary distribution - a plain Java application runnable on PCs +import Terasology_dist_gradle.ValidateZipDistribution import org.apache.tools.ant.filters.FixCrLfFilter import org.apache.tools.ant.taskdefs.condition.Os import java.text.SimpleDateFormat @@ -10,6 +11,7 @@ import java.util.* plugins { application + `terasology-dist` } // Grab all the common stuff like plugins to use, artifact repositories, code analysis config @@ -241,7 +243,7 @@ val createVersionFile = tasks.register("createVersionFile") { filter(FixCrLfFilter::class, "eol" to FixCrLfFilter.CrLf.newInstance("crlf")) } -tasks.register("distForLauncher") { +val distForLauncher = tasks.register("distForLauncher") { group = "terasology dist" description = "Bundles the project to a Launcher-compatible layout." @@ -273,6 +275,42 @@ tasks.register("distForLauncher") { }) } +tasks.register("testDistForLauncher") { + description = "Validates locations in distForLauncher." + + fromTask(distForLauncher) + + doLast { + val theFile = zipFile.get().asFile + assertEquals("Terasology.zip", theFile.name) + + assertContainsPath("libs/Terasology.jar") + assertContainsPath("/Terasology.bat") + } +} + +tasks.register("testDistZip") { + description = "Validates locations in distZip." + + fromTask(tasks.named("distZip")) + + doLast { + assertContainsPath("*/lib/Terasology.jar") + + val rootFiles = tree.matching { + include("/*") + } + if (!rootFiles.isEmpty) { + fail("Expected a single root directory, but root contains files ${rootFiles.files.map { it.name }}") + } + } +} + +tasks.register("testDist") { + group = "verification" + dependsOn("testDistForLauncher", "testDistZip") +} + class ScriptClasspathRewriter(file: FileCopyDetails, val oldDirectory: String, val newDirectory: String) : Transformer { private val isBatchFile = file.name.endsWith(".bat") From 1d9d8aacf5777e87512cf2df55d810829bc2ea22 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 29 Jan 2021 20:39:45 -0800 Subject: [PATCH 166/259] fix(build): keep start scripts inside distZip's root directory --- facades/PC/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index ec8b29a9999..0bc1b729c14 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -70,7 +70,7 @@ val displayVersion = versionBase application { applicationName = "Terasology" - executableDir = "/" + executableDir = "" mainClass.set(extra.get("mainClassName") as String) } @@ -296,6 +296,7 @@ tasks.register("testDistZip") { doLast { assertContainsPath("*/lib/Terasology.jar") + assertContainsPath("*/Terasology.bat") val rootFiles = tree.matching { include("/*") From 46c88d76ae567bea83b39213300a3b36161556e3 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 30 Jan 2021 00:59:42 -0800 Subject: [PATCH 167/259] chore(build): remove unused asm-related dependencies (#4440) These haven't been in use in core recently. --- engine/build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index a6449c7ba9f..bbf395b8526 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -92,12 +92,6 @@ dependencies { api group: 'com.miglayout', name: 'miglayout-core', version: '5.0' implementation group: 'de.matthiasmann.twl', name: 'PNGDecoder', version: '1111' - // Assembly & Bytecode - implementation group: 'org.ow2.asm', name: 'asm', version: '5.0.3' - implementation group: 'org.ow2.asm', name: 'asm-tree', version: '5.0.4' - implementation group: 'org.ow2.asm', name: 'asm-util', version: '5.0.4' - implementation group: 'org.ow2.asm', name: 'asm-commons', version: '5.0.4' - // Logging and audio implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21' implementation group: 'com.projectdarkstar.ext.jorbis', name: 'jorbis', version: '0.0.17' From 242beefc0624b3d8d70cf9ec77890d74cd0909a1 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 30 Jan 2021 16:55:29 +0100 Subject: [PATCH 168/259] feat(block/family): add default forwarding to JOML API (#4441) * feat(block/family): add default forwarding to JOML API on MultiConnectFamily * feat(block/family): add default forwarding to JOML API on UpdatesWithNeighboursFamily Contributes to #3832 --- .../block/family/MultiConnectFamily.java | 24 +++---------------- .../family/UpdatesWithNeighboursFamily.java | 14 ++++++++--- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java index 7e602e225f4..ec306eedd5b 100644 --- a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java @@ -91,7 +91,9 @@ public MultiConnectFamily(BlockFamilyDefinition definition, BlockBuilderHelper b * Use the JOML implementation instead: {@link #connectionCondition(Vector3ic, Side)}. */ @Deprecated - protected abstract boolean connectionCondition(Vector3i blockLocation, Side connectSide); + protected boolean connectionCondition(Vector3i blockLocation, Side connectSide) { + return connectionCondition(JomlUtil.from(blockLocation), connectSide); + } /** * A condition to return true if the block should have a connection on the given side @@ -103,7 +105,6 @@ public MultiConnectFamily(BlockFamilyDefinition definition, BlockBuilderHelper b */ protected abstract boolean connectionCondition(Vector3ic blockLocation, Side connectSide); - /** * The sides of the block that can be connected to. * Example: In a family like RomanColumn, this method only returns SideBitFlag.getSides(Side.TOP, Side.BOTTOM) @@ -195,25 +196,6 @@ public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side d return getBlockForPlacement(data); } - /** - * Update the block then a neighbor changes - * - * @param location The location of the block - * @param oldBlock What the block was before the neighbor updated - * - * @return The block from the family to be placed - */ - @Override - public Block getBlockForNeighborUpdate(Vector3i location, Block oldBlock) { - byte connections = 0; - for (Side connectSide : SideBitFlag.getSides(getConnectionSides())) { - if (this.connectionCondition(location, connectSide)) { - connections += SideBitFlag.getSide(connectSide); - } - } - return blocks.get(connections); - } - @Override public Block getBlockForNeighborUpdate(Vector3ic location, Block oldBlock) { byte connections = 0; diff --git a/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java b/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java index 44958dfea4b..9f082b964cf 100644 --- a/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java @@ -16,6 +16,7 @@ package org.terasology.world.block.family; import org.joml.Vector3ic; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; @@ -29,10 +30,17 @@ public interface UpdatesWithNeighboursFamily extends BlockFamily { * Use the JOML implementation instead: {@link #getBlockForNeighborUpdate(Vector3ic, Block)}. **/ @Deprecated - Block getBlockForNeighborUpdate(Vector3i location, Block oldBlock); + default Block getBlockForNeighborUpdate(Vector3i location, Block oldBlock) { + return getBlockForNeighborUpdate(JomlUtil.from(location), oldBlock); + } /** - * Update called when a neighbor block changes - **/ + * Update the block when a neighbor changes + * + * @param location the location of the block + * @param oldBlock the block before the neighbor was updated + * + * @return The block from the family to be placed + */ Block getBlockForNeighborUpdate(Vector3ic location, Block oldBlock); } From faa9eff667aa46a24708ba73de22be8c10f1f688 Mon Sep 17 00:00:00 2001 From: jdrueckert Date: Sat, 30 Jan 2021 17:40:23 +0100 Subject: [PATCH 169/259] feat(JOML): migrate logic.players (#4442) * feat(JOML): migrate logic.players * chore: remove unnecessary qualification --- .../logic/location/LocationComponent.java | 17 +- .../logic/players/CameraClientSystem.java | 27 +-- .../logic/players/DebugControlSystem.java | 3 +- .../terasology/logic/players/LocalPlayer.java | 155 ++++-------------- .../logic/players/LocalPlayerSystem.java | 20 +-- .../logic/players/MenuControlSystem.java | 19 +-- .../logic/players/PlayerSystem.java | 18 +- .../rendering/cameras/ViewFrustum.java | 19 +-- .../RemoteChunkProvider.java | 32 ++-- 9 files changed, 71 insertions(+), 239 deletions(-) diff --git a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java index d8bf5b7b8bb..bd1e1105794 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java @@ -1,18 +1,5 @@ -/* - * Copyright 2014 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.location; import com.google.common.collect.Lists; diff --git a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java index eda977ef020..0733c73d928 100644 --- a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java @@ -1,20 +1,9 @@ -/* - * Copyright 2015 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.entitySystem.entity.EntityBuilder; import org.terasology.entitySystem.entity.EntityManager; import org.terasology.entitySystem.entity.EntityRef; @@ -32,8 +21,7 @@ import org.terasology.logic.permission.PermissionManager; import org.terasology.logic.players.event.OnPlayerSpawnedEvent; import org.terasology.logic.players.event.ResetCameraEvent; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; +import org.terasology.math.JomlUtil; import org.terasology.network.ClientComponent; import org.terasology.registry.In; @@ -129,9 +117,10 @@ private void mountCamera() { LocationComponent cameraLocation = clientComponent.camera.getComponent(LocationComponent.class); // if the camera already has a location, use that as the relative position of the camera if (cameraLocation != null) { - Location.attachChild(targetEntityForCamera, clientComponent.camera, cameraLocation.getLocalPosition(), new Quat4f(Quat4f.IDENTITY)); + + Location.attachChild(targetEntityForCamera, clientComponent.camera, JomlUtil.from(cameraLocation.getLocalPosition()), new Quaternionf()); } else { - Location.attachChild(targetEntityForCamera, clientComponent.camera, Vector3f.zero(), new Quat4f(Quat4f.IDENTITY)); + Location.attachChild(targetEntityForCamera, clientComponent.camera, new Vector3f(0, 0, 0), new Quaternionf()); } } } diff --git a/engine/src/main/java/org/terasology/logic/players/DebugControlSystem.java b/engine/src/main/java/org/terasology/logic/players/DebugControlSystem.java index 8ed90fc343e..1c6e260bc2f 100644 --- a/engine/src/main/java/org/terasology/logic/players/DebugControlSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/DebugControlSystem.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; @@ -17,7 +17,6 @@ import org.terasology.input.events.MouseAxisEvent; import org.terasology.logic.characters.CharacterComponent; import org.terasology.logic.debug.DebugProperties; -import org.terasology.logic.time.TimeResynchEvent; import org.terasology.logic.players.event.WorldtimeResetEvent; import org.terasology.network.ClientComponent; import org.terasology.registry.In; diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java index a0857190559..3eea14ee23d 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java @@ -1,22 +1,10 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; import com.google.common.collect.Sets; import org.joml.Quaternionf; +import org.joml.Vector3f; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.characters.CharacterComponent; import org.terasology.logic.characters.CharacterMovementComponent; @@ -25,9 +13,7 @@ import org.terasology.logic.characters.events.ActivationRequest; import org.terasology.logic.location.LocationComponent; import org.terasology.math.Direction; -import org.terasology.math.JomlUtil; import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.network.ClientComponent; import org.terasology.physics.HitResult; import org.terasology.physics.Physics; @@ -100,32 +86,7 @@ public EntityRef getClientInfoEntity() { public boolean isValid() { EntityRef characterEntity = getCharacterEntity(); return characterEntity.exists() && characterEntity.hasComponent(LocationComponent.class) && characterEntity.hasComponent(CharacterComponent.class) - && characterEntity.hasComponent(CharacterMovementComponent.class); - } - - /** - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getPosition() { - return getPosition(new Vector3f()); - } - - /** - * @param out - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getPosition(Vector3f out) { - LocationComponent location = getCharacterEntity().getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { - return out; - } - return location.getWorldPosition(out); + && characterEntity.hasComponent(CharacterMovementComponent.class); } /** @@ -134,10 +95,10 @@ public Vector3f getPosition(Vector3f out) { * @param dest will hold the result * @return dest */ - public org.joml.Vector3f getPosition(org.joml.Vector3f dest) { + public Vector3f getPosition(Vector3f dest) { LocationComponent location = getCharacterEntity().getComponent(LocationComponent.class); if (location != null) { - org.joml.Vector3f result = location.getWorldPosition(new org.joml.Vector3f()); + Vector3f result = location.getWorldPosition(new Vector3f()); if (result.isFinite()) { //TODO: MP finite check seems to hide a larger underlying problem dest.set(result); } @@ -148,12 +109,12 @@ public org.joml.Vector3f getPosition(org.joml.Vector3f dest) { /** * @return * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getRotation(Quaternionf)}. + * {@link #getRotation(Quaternionf)}. */ @Deprecated public Quat4f getRotation() { LocationComponent location = getCharacterEntity().getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { + if (location == null || Float.isNaN(location.getWorldPosition(new Vector3f()).x)) { return new Quat4f(Quat4f.IDENTITY); } return location.getWorldRotation(); @@ -175,50 +136,21 @@ public Quaternionf getRotation(Quaternionf dest) { } return dest; } - /** - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getViewPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getViewPosition() { - return getViewPosition(new Vector3f()); - } /** - * @param out - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getViewPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getViewPosition(Vector3f out) { - ClientComponent clientComponent = getClientEntity().getComponent(ClientComponent.class); - if (clientComponent == null) { - return out; - } - LocationComponent location = clientComponent.camera.getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { - return getPosition(); - } - - return location.getWorldPosition(out); - } - - /** - * position of camera if one is present else use {@link #getPosition(org.joml.Vector3f)} + * position of camera if one is present else use {@link #getPosition(Vector3f)} * * @param dest will hold the result * @return dest */ - public org.joml.Vector3f getViewPosition(org.joml.Vector3f dest) { + public Vector3f getViewPosition(Vector3f dest) { ClientComponent clientComponent = getClientEntity().getComponent(ClientComponent.class); if (clientComponent == null) { return dest; } LocationComponent location = clientComponent.camera.getComponent(LocationComponent.class); if (location != null) { - org.joml.Vector3f result = location.getWorldPosition(new org.joml.Vector3f()); + Vector3f result = location.getWorldPosition(new Vector3f()); if (result.isFinite()) { //TODO: MP finite check seems to hide a larger underlying problem dest.set(result); return dest; @@ -230,7 +162,7 @@ public org.joml.Vector3f getViewPosition(org.joml.Vector3f dest) { /** * @return * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getViewRotation(Quaternionf)}. + * {@link #getViewRotation(Quaternionf)}. */ @Deprecated public Quat4f getViewRotation() { @@ -239,7 +171,7 @@ public Quat4f getViewRotation() { return new Quat4f(Quat4f.IDENTITY); } LocationComponent location = clientComponent.camera.getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition().x)) { + if (location == null || Float.isNaN(location.getWorldPosition(new Vector3f()).x)) { return getRotation(); } @@ -247,7 +179,7 @@ public Quat4f getViewRotation() { } /** - * orientation of camera if one is present else use {@link #getPosition(org.joml.Vector3f)} + * orientation of camera if one is present else use {@link #getPosition(Vector3f)} * * @param dest will hold the result * @return dest @@ -274,39 +206,12 @@ public Quaternionf getViewRotation(Quaternionf dest) { * @param dest will hold the result * @return dest */ - public org.joml.Vector3f getViewDirection(org.joml.Vector3f dest) { + public Vector3f getViewDirection(Vector3f dest) { Quaternionf rot = getViewRotation(new Quaternionf()); return rot.transform(Direction.FORWARD.asVector3f(), dest); } - /** - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getViewDirection(org.joml.Vector3f)} - */ - @Deprecated - public Vector3f getViewDirection() { - Quat4f rot = getViewRotation(); - // TODO: Put a generator for direction vectors in a util class somewhere - // And just put quaternion -> vector somewhere too - Vector3f dir = Direction.FORWARD.getVector3f(); - return rot.rotate(dir, dir); - } - /** - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getVelocity(org.joml.Vector3f)} - */ - @Deprecated - public Vector3f getVelocity() { - CharacterMovementComponent movement = getCharacterEntity().getComponent(CharacterMovementComponent.class); - if (movement != null) { - return JomlUtil.from(movement.getVelocity()); - } - return new Vector3f(); - } - - public org.joml.Vector3f getVelocity(org.joml.Vector3f dest) { + public Vector3f getVelocity(Vector3f dest) { CharacterMovementComponent movement = getCharacterEntity().getComponent(CharacterMovementComponent.class); if (movement != null) { return dest.set(movement.getVelocity()); @@ -349,32 +254,36 @@ boolean activateTargetAsClient() { private boolean activateTargetOrOwnedEntity(EntityRef usedOwnedEntity) { EntityRef character = getCharacterEntity(); CharacterComponent characterComponent = character.getComponent(CharacterComponent.class); - org.joml.Vector3f direction = getViewDirection(new org.joml.Vector3f()); - org.joml.Vector3f originPos = getViewPosition(new org.joml.Vector3f()); + Vector3f direction = getViewDirection(new Vector3f()); + Vector3f originPos = getViewPosition(new Vector3f()); if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.RECORDING) { this.directionAndOriginPosRecorderList.getTargetOrOwnedEntityDirectionAndOriginPosRecorder().add(direction, originPos); } else if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) { - org.joml.Vector3f[] data = this.directionAndOriginPosRecorderList.getTargetOrOwnedEntityDirectionAndOriginPosRecorder().poll(); + Vector3f[] data = + this.directionAndOriginPosRecorderList.getTargetOrOwnedEntityDirectionAndOriginPosRecorder().poll(); direction = data[0]; originPos = data[1]; } boolean ownedEntityUsage = usedOwnedEntity.exists(); int activationId = nextActivationId++; Physics physics = CoreRegistry.get(Physics.class); - HitResult result = physics.rayTrace(originPos, direction, characterComponent.interactionRange, Sets.newHashSet(character), CharacterSystem.DEFAULTPHYSICSFILTER); + HitResult result = physics.rayTrace(originPos, direction, characterComponent.interactionRange, + Sets.newHashSet(character), CharacterSystem.DEFAULTPHYSICSFILTER); boolean eventWithTarget = result.isHit(); if (eventWithTarget) { EntityRef activatedObject = usedOwnedEntity.exists() ? usedOwnedEntity : result.getEntity(); activatedObject.send(new ActivationPredicted(character, result.getEntity(), originPos, direction, - result.getHitPoint(), result.getHitNormal(), activationId)); - character.send(new ActivationRequest(character, ownedEntityUsage, usedOwnedEntity, eventWithTarget, result.getEntity(), - originPos, direction, result.getHitPoint(), result.getHitNormal(), activationId)); + result.getHitPoint(), result.getHitNormal(), activationId)); + character.send(new ActivationRequest(character, ownedEntityUsage, usedOwnedEntity, eventWithTarget, + result.getEntity(), + originPos, direction, result.getHitPoint(), result.getHitNormal(), activationId)); return true; } else if (ownedEntityUsage) { usedOwnedEntity.send(new ActivationPredicted(character, EntityRef.NULL, originPos, direction, - originPos, new org.joml.Vector3f(), activationId)); - character.send(new ActivationRequest(character, ownedEntityUsage, usedOwnedEntity, eventWithTarget, EntityRef.NULL, - originPos, direction, originPos, new org.joml.Vector3f(), activationId)); + originPos, new Vector3f(), activationId)); + character.send(new ActivationRequest(character, ownedEntityUsage, usedOwnedEntity, eventWithTarget, + EntityRef.NULL, + originPos, direction, originPos, new Vector3f(), activationId)); return true; } return false; @@ -383,7 +292,9 @@ private boolean activateTargetOrOwnedEntity(EntityRef usedOwnedEntity) { @Override public String toString() { + Vector3f pos = getPosition(new Vector3f()); return String.format("player (x: %.2f, y: %.2f, z: %.2f | x: %.2f, y: %.2f, z: %.2f)", - getPosition().x, getPosition().y, getPosition().z, getViewDirection().x, getViewDirection().y, getViewDirection().z); + pos.x, pos.y, pos.z, getViewDirection(new Vector3f()).x, + getViewDirection(new Vector3f()).y, getViewDirection(new Vector3f()).z); } } diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java index d4674b918a1..4ce8dca5c6a 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayerSystem.java @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; import org.joml.Math; @@ -52,7 +39,6 @@ import org.terasology.input.events.MouseAxisEvent; import org.terasology.input.events.MouseAxisEvent.MouseAxis; import org.terasology.joml.geom.AABBf; -import org.terasology.joml.geom.AABBfc; import org.terasology.logic.characters.CharacterComponent; import org.terasology.logic.characters.CharacterHeldItemComponent; import org.terasology.logic.characters.CharacterMoveInputEvent; @@ -65,8 +51,6 @@ import org.terasology.logic.location.LocationComponent; import org.terasology.logic.players.event.LocalPlayerInitializedEvent; import org.terasology.logic.players.event.OnPlayerSpawnedEvent; -import org.terasology.math.AABB; -import org.terasology.math.JomlUtil; import org.terasology.network.ClientComponent; import org.terasology.network.NetworkMode; import org.terasology.network.NetworkSystem; diff --git a/engine/src/main/java/org/terasology/logic/players/MenuControlSystem.java b/engine/src/main/java/org/terasology/logic/players/MenuControlSystem.java index 8c6a029ef9f..bd13f00877e 100644 --- a/engine/src/main/java/org/terasology/logic/players/MenuControlSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/MenuControlSystem.java @@ -1,22 +1,10 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; import org.terasology.audio.AudioManager; +import org.terasology.engine.Time; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; @@ -38,7 +26,6 @@ import org.terasology.rendering.nui.layers.ingame.OnlinePlayersOverlay; import org.terasology.rendering.opengl.ScreenGrabber; import org.terasology.utilities.Assets; -import org.terasology.engine.Time; /** diff --git a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java index 98057955e94..a1c886f62c0 100644 --- a/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/PlayerSystem.java @@ -1,18 +1,5 @@ -/* - * Copyright 2016 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.logic.players; @@ -40,7 +27,6 @@ import org.terasology.logic.players.event.OnPlayerRespawnedEvent; import org.terasology.logic.players.event.OnPlayerSpawnedEvent; import org.terasology.logic.players.event.RespawnRequestEvent; -import org.terasology.math.JomlUtil; import org.terasology.network.Client; import org.terasology.network.ClientComponent; import org.terasology.network.NetworkSystem; diff --git a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java index 0aea2f73f0c..d254c72b5dd 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/ViewFrustum.java @@ -1,18 +1,5 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.cameras; import org.terasology.joml.geom.AABBf; @@ -159,7 +146,7 @@ public boolean intersects(AABB aabb) { */ public boolean intersects(AABBfc aabb) { - Vector3f cp = CoreRegistry.get(LocalPlayer.class).getViewPosition(); + Vector3f cp = JomlUtil.from(CoreRegistry.get(LocalPlayer.class).getViewPosition(new org.joml.Vector3f())); for (int i = 0; i < 6; i++) { if (planes[i].getA() * (aabb.minX() - cp.x) + planes[i].getB() * (aabb.minY() - cp.y) + planes[i].getC() * (aabb.maxZ() - cp.z) + planes[i].getD() > 0) { diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index 708d4eb045a..f4041d90508 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.chunks.remoteChunkProvider; @@ -6,6 +6,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Queues; +import org.joml.Vector3f; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,6 +23,7 @@ import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.event.BeforeChunkUnload; import org.terasology.world.chunks.event.OnChunkLoaded; import org.terasology.world.chunks.pipeline.ChunkProcessingPipeline; @@ -106,7 +108,7 @@ public void update() { } Chunk chunk; while ((chunk = readyChunks.poll()) != null) { - Chunk oldChunk = chunkCache.put(chunk.getPosition(), chunk); + Chunk oldChunk = chunkCache.put(JomlUtil.from(chunk.getPosition(new org.joml.Vector3i())), chunk); if (oldChunk != null) { oldChunk.dispose(); } @@ -194,7 +196,7 @@ public void restart() { @Override public ChunkViewCore getLocalView(Vector3i centerChunkPos) { - Region3i region = Region3i.createFromCenterExtents(centerChunkPos, ChunkConstants.LOCAL_REGION_EXTENTS); + BlockRegion region = new BlockRegion(JomlUtil.from(centerChunkPos)).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(centerChunkPos) != null) { return createWorldView(region, Vector3i.one()); } @@ -203,28 +205,28 @@ public ChunkViewCore getLocalView(Vector3i centerChunkPos) { @Override public ChunkViewCore getSubviewAroundBlock(Vector3i blockPos, int extent) { - Region3i region = ChunkMath.getChunkRegionAroundWorldPos(blockPos, extent); - return createWorldView(region, new Vector3i(-region.min().x, -region.min().y, -region.min().z)); + BlockRegion region = ChunkMath.getChunkRegionAroundWorldPos(JomlUtil.from(blockPos), extent); + return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } @Override public ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos) { - Region3i region = Region3i.createFromCenterExtents(chunkPos, ChunkConstants.LOCAL_REGION_EXTENTS); + BlockRegion region = new BlockRegion(JomlUtil.from(chunkPos)).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(chunkPos) != null) { - return createWorldView(region, new Vector3i(-region.min().x, -region.min().y, -region.min().z)); + return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } return null; } - private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { - Chunk[] chunks = new Chunk[region.sizeX() * region.sizeY() * region.sizeZ()]; - for (Vector3i chunkPos : region) { - Chunk chunk = chunkCache.get(chunkPos); - chunkPos.sub(region.minX(), region.minY(), region.minZ()); - int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); + private ChunkViewCore createWorldView(BlockRegion region, Vector3i offset) { + Chunk[] chunks = new Chunk[region.getSizeX() * region.getSizeY() * region.getSizeZ()]; + for (Vector3ic chunkPos : region) { + Chunk chunk = chunkCache.get(JomlUtil.from(chunkPos)); + chunkPos.sub(region.minX(), region.minY(), region.minZ(), new org.joml.Vector3i()); + int index = TeraMath.calculate3DArrayIndex(JomlUtil.from(chunkPos), JomlUtil.from(region.getSize(new org.joml.Vector3i()))); chunks[index] = chunk; } - return new ChunkViewCoreImpl(chunks, JomlUtil.from(region), JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); + return new ChunkViewCoreImpl(chunks, region, JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); } @Override @@ -245,7 +247,7 @@ public int compare(Future o1, Future o2) { } private int score(PositionFuture task) { - return (int) ChunkMath.calcChunkPos(JomlUtil.from(localPlayer.getPosition()), new org.joml.Vector3i()).distance(task.getPosition()); + return (int) Chunks.toChunkPos(localPlayer.getPosition(new Vector3f()), new org.joml.Vector3i()).distance(task.getPosition()); } } } From 0e82184408ae6f49c66c44f9915aba93d2ec5d34 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 30 Jan 2021 09:49:18 -0800 Subject: [PATCH 170/259] fix(build): use .flatMap to unwrap Provider> as recommended by https://discuss.gradle.org/t/un-nesting-provider-provider/38904 --- buildSrc/src/main/kotlin/terasology-dist.gradle.kts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts index 670f15980ed..36bd9bd406d 100644 --- a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts @@ -22,10 +22,7 @@ open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : } fun fromTask(taskProvider: Provider) { - // FIXME: is it right to use .get here? - // https://discuss.gradle.org/t/un-nesting-provider-provider/38904 - val fileProvider = taskProvider.map { it.archiveFile }.get() - zipFile.set(fileProvider) + zipFile.set(taskProvider.flatMap { it.archiveFile }) } fun assertEquals(expected: Any, actual: Any, message: String? = null) = From c195d68a40c52013c2d134d17029104d004961ee Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 30 Jan 2021 22:05:49 +0100 Subject: [PATCH 171/259] feat(JOML): remove deprecated API in favor of JOML for BlockFamily (#4443) --- .../block/family/AttachedToSurfaceFamily.java | 23 +--------- .../world/block/family/BlockFamily.java | 31 +------------ .../CeilingSupportingHorizontalFamily.java | 27 +---------- .../world/block/family/FreeformFamily.java | 33 +------------ .../world/block/family/HorizontalFamily.java | 32 +------------ .../block/family/MultiConnectFamily.java | 46 ++----------------- .../world/block/family/SymmetricFamily.java | 24 +--------- .../family/UpdatesWithNeighboursFamily.java | 12 ----- 8 files changed, 15 insertions(+), 213 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/family/AttachedToSurfaceFamily.java b/engine/src/main/java/org/terasology/world/block/family/AttachedToSurfaceFamily.java index c18cdff78b0..f4ceba0bd96 100644 --- a/engine/src/main/java/org/terasology/world/block/family/AttachedToSurfaceFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/AttachedToSurfaceFamily.java @@ -1,25 +1,11 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import com.google.common.collect.Maps; import org.terasology.math.Pitch; import org.terasology.math.Rotation; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.naming.Name; import org.terasology.world.block.Block; import org.terasology.world.block.BlockBuilderHelper; @@ -87,11 +73,6 @@ public Block getBlockForPlacement(BlockPlacementData data) { return blocks.get(data.attachmentSide); } - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - return blocks.get(attachmentSide); - } - @Override public Block getArchetypeBlock() { return archetype; diff --git a/engine/src/main/java/org/terasology/world/block/family/BlockFamily.java b/engine/src/main/java/org/terasology/world/block/family/BlockFamily.java index 2d8a9f6c25a..b8113af7f9a 100644 --- a/engine/src/main/java/org/terasology/world/block/family/BlockFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/BlockFamily.java @@ -1,23 +1,8 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import org.terasology.assets.ResourceUrn; -import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.block.BlockUri; @@ -48,18 +33,6 @@ public interface BlockFamily { */ Block getBlockForPlacement(BlockPlacementData data); - /** - * Get the block that is appropriate for placement in the given situation - * - * @param location The location where the block is going to be placed. - * @param attachmentSide The side of the block which this block is being attached to, e.g. Top if the block is being placed on the ground - * @param direction A secondary direction after the attachment side that determines the facing of the block. - * @return The appropriate block - * @deprecated This method is scheduled for removal, use this one instead: {@link #getBlockForPlacement(BlockPlacementData)}. - */ - @Deprecated - Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction); - /** * @return The base block defining the block group. Can be used for orientation-irrelevant behaviours */ diff --git a/engine/src/main/java/org/terasology/world/block/family/CeilingSupportingHorizontalFamily.java b/engine/src/main/java/org/terasology/world/block/family/CeilingSupportingHorizontalFamily.java index a7e3e565f64..8f784a1925c 100644 --- a/engine/src/main/java/org/terasology/world/block/family/CeilingSupportingHorizontalFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/CeilingSupportingHorizontalFamily.java @@ -1,18 +1,5 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import com.google.common.collect.Maps; @@ -21,7 +8,6 @@ import org.terasology.math.Rotation; import org.terasology.math.Side; import org.terasology.math.Yaw; -import org.terasology.math.geom.Vector3i; import org.terasology.naming.Name; import org.terasology.world.block.Block; import org.terasology.world.block.BlockBuilderHelper; @@ -130,15 +116,6 @@ public Block getBlockForPlacement(BlockPlacementData data) { return blocks.get(ExtendedSide.getExtendedSideFor(mainSide, blockDirection)); } - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - if (attachmentSide == Side.BOTTOM) { - return blocks.get(ExtendedSide.getExtendedSideFor(Side.BOTTOM, direction)); - } else { - return blocks.get(ExtendedSide.getExtendedSideFor(Side.TOP, direction)); - } - } - @Override public Block getArchetypeBlock() { return blocks.get(ExtendedSide.getExtendedSideFor(Side.TOP, Side.FRONT)); diff --git a/engine/src/main/java/org/terasology/world/block/family/FreeformFamily.java b/engine/src/main/java/org/terasology/world/block/family/FreeformFamily.java index 583944ecb57..8b753f90571 100644 --- a/engine/src/main/java/org/terasology/world/block/family/FreeformFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/FreeformFamily.java @@ -1,18 +1,5 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import com.google.common.collect.Maps; @@ -20,7 +7,6 @@ import org.slf4j.LoggerFactory; import org.terasology.math.Rotation; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.naming.Name; import org.terasology.world.block.Block; import org.terasology.world.block.BlockBuilderHelper; @@ -87,21 +73,6 @@ public Block getBlockForPlacement(BlockPlacementData data) { } } - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - if (archetypeBlock == null) { - if (attachmentSide.isHorizontal()) { - return blocks.get(attachmentSide); - } - if (direction != null) { - return blocks.get(direction); - } else { - return blocks.get(Side.FRONT); - } - } - return archetypeBlock; - } - @Override public Block getArchetypeBlock() { if (archetypeBlock == null) { diff --git a/engine/src/main/java/org/terasology/world/block/family/HorizontalFamily.java b/engine/src/main/java/org/terasology/world/block/family/HorizontalFamily.java index a711cdecc73..46f8f06b220 100644 --- a/engine/src/main/java/org/terasology/world/block/family/HorizontalFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/HorizontalFamily.java @@ -1,24 +1,10 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import com.google.common.collect.Maps; import org.terasology.math.Rotation; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.naming.Name; import org.terasology.world.block.Block; import org.terasology.world.block.BlockBuilderHelper; @@ -89,18 +75,6 @@ public Block getBlockForPlacement(BlockPlacementData data) { } } - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - if (attachmentSide.isHorizontal()) { - return blocks.get(attachmentSide); - } - if (direction != null) { - return blocks.get(direction); - } else { - return blocks.get(Side.FRONT); - } - } - @Override public Block getArchetypeBlock() { return blocks.get(this.getArchetypeSide()); @@ -138,6 +112,4 @@ public Side getSide(Block block) { } return null; } - - } diff --git a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java index ec306eedd5b..5afbe2b8066 100644 --- a/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/MultiConnectFamily.java @@ -1,32 +1,16 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; import com.google.common.collect.Sets; import gnu.trove.map.TByteObjectMap; import gnu.trove.map.hash.TByteObjectHashMap; -import org.joml.Vector3f; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.math.JomlUtil; import org.terasology.math.Rotation; import org.terasology.math.Side; import org.terasology.math.SideBitFlag; -import org.terasology.math.geom.Vector3i; import org.terasology.naming.Name; import org.terasology.registry.In; import org.terasology.world.BlockEntityRegistry; @@ -80,21 +64,6 @@ public MultiConnectFamily(BlockFamilyDefinition definition, BlockBuilderHelper b super(definition, blockBuilder); } - /** - * A condition to return true if the block should have a connection on the given side - * - * @param blockLocation The position of the block in question - * @param connectSide The side to determine connection for - * - * @return A boolean indicating if the block should connect on the given side - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #connectionCondition(Vector3ic, Side)}. - */ - @Deprecated - protected boolean connectionCondition(Vector3i blockLocation, Side connectSide) { - return connectionCondition(JomlUtil.from(blockLocation), connectSide); - } - /** * A condition to return true if the block should have a connection on the given side * @@ -180,22 +149,13 @@ public Set registerBlock(BlockUri root, BlockFamilyDefinition definition, public Block getBlockForPlacement(BlockPlacementData data) { byte connections = 0; for (Side connectSide : SideBitFlag.getSides(getConnectionSides())) { - if (this.connectionCondition(JomlUtil.from(data.blockPosition), connectSide)) { + if (this.connectionCondition(data.blockPosition, connectSide)) { connections += SideBitFlag.getSide(connectSide); } } return blocks.get(connections); } - /** - * {@inheritDoc} - */ - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - BlockPlacementData data = new BlockPlacementData(JomlUtil.from(location), attachmentSide, new Vector3f()); - return getBlockForPlacement(data); - } - @Override public Block getBlockForNeighborUpdate(Vector3ic location, Block oldBlock) { byte connections = 0; diff --git a/engine/src/main/java/org/terasology/world/block/family/SymmetricFamily.java b/engine/src/main/java/org/terasology/world/block/family/SymmetricFamily.java index 0e594f2ed62..1ecc42911c0 100644 --- a/engine/src/main/java/org/terasology/world/block/family/SymmetricFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/SymmetricFamily.java @@ -1,22 +1,7 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block.family; -import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; import org.terasology.world.block.BlockBuilderHelper; import org.terasology.world.block.BlockUri; @@ -57,11 +42,6 @@ public Block getBlockForPlacement(BlockPlacementData data) { return block; } - @Override - public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) { - return block; - } - @Override public Block getArchetypeBlock() { return block; diff --git a/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java b/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java index 9f082b964cf..4b2c06c5138 100644 --- a/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java +++ b/engine/src/main/java/org/terasology/world/block/family/UpdatesWithNeighboursFamily.java @@ -16,24 +16,12 @@ package org.terasology.world.block.family; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; /** * Interface for Block family that gets updated by a change in a neighbor block. */ public interface UpdatesWithNeighboursFamily extends BlockFamily { - /** - * Update called when a neighbor block changes - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #getBlockForNeighborUpdate(Vector3ic, Block)}. - **/ - @Deprecated - default Block getBlockForNeighborUpdate(Vector3i location, Block oldBlock) { - return getBlockForNeighborUpdate(JomlUtil.from(location), oldBlock); - } - /** * Update the block when a neighbor changes * From ab30896249cd12a115d63703c01204d89f578779 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 30 Jan 2021 23:38:59 +0100 Subject: [PATCH 172/259] feat(JOML): migrate `Location` system and (parts of) `LocationComponent` (#4444) --- .../entity/internal/PojoEntityPool.java | 4 +- .../entitySystem/sectors/SectorUtil.java | 2 +- .../logic/inventory/events/DropItemEvent.java | 20 +-- .../terasology/logic/location/Location.java | 80 ++++------- .../logic/location/LocationComponent.java | 130 +----------------- .../terasology/logic/players/LocalPlayer.java | 18 +-- .../world/block/BlockComponent.java | 4 +- .../internal/EntityAwareWorldProvider.java | 8 +- 8 files changed, 45 insertions(+), 221 deletions(-) diff --git a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java index dab6261233b..2c84b40dd99 100644 --- a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java +++ b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java @@ -138,10 +138,10 @@ private EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation, bool } if (position != null) { - loc.setWorldPosition(position); + loc.setWorldPosition(JomlUtil.from(position)); } if (rotation != null) { - loc.setWorldRotation(rotation); + loc.setWorldRotation(JomlUtil.from(rotation)); } return builder.build(); diff --git a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java index fcffe5e2a14..95ee9769bbf 100644 --- a/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java +++ b/engine/src/main/java/org/terasology/entitySystem/sectors/SectorUtil.java @@ -82,7 +82,7 @@ public static void addChunksToRegionComponent(EntityRef entity, Collection - *
  • The chunk in which the {@link LocationComponent#getWorldPosition()} resides, if any
  • + *
  • The chunk in which the {@link LocationComponent#getWorldPosition(Vector3f)} resides, if any
  • *
  • The set of chunks in {@link SectorRegionComponent#chunks}, if any
  • * * diff --git a/engine/src/main/java/org/terasology/logic/inventory/events/DropItemEvent.java b/engine/src/main/java/org/terasology/logic/inventory/events/DropItemEvent.java index 6046cc484d8..de65490a484 100644 --- a/engine/src/main/java/org/terasology/logic/inventory/events/DropItemEvent.java +++ b/engine/src/main/java/org/terasology/logic/inventory/events/DropItemEvent.java @@ -15,9 +15,9 @@ */ package org.terasology.logic.inventory.events; +import org.joml.Vector3f; +import org.joml.Vector3fc; import org.terasology.entitySystem.event.Event; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; import org.terasology.network.ServerEvent; /** @@ -25,24 +25,16 @@ */ @ServerEvent public class DropItemEvent implements Event { - private Vector3f position; + private Vector3f position = new Vector3f(); public DropItemEvent() { } - /** - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #DropItemEvent(org.joml.Vector3f)}. - */ - public DropItemEvent(Vector3f position) { - this.position = position; + public DropItemEvent(Vector3fc position) { + this.position.set(position); } - public DropItemEvent(org.joml.Vector3f position) { - this.position = JomlUtil.from(position); - } - - public Vector3f getPosition() { + public Vector3fc getPosition() { return position; } } diff --git a/engine/src/main/java/org/terasology/logic/location/Location.java b/engine/src/main/java/org/terasology/logic/location/Location.java index d9fbcbd9c9f..e1d50d04898 100644 --- a/engine/src/main/java/org/terasology/logic/location/Location.java +++ b/engine/src/main/java/org/terasology/logic/location/Location.java @@ -17,6 +17,7 @@ package org.terasology.logic.location; import org.joml.Quaternionfc; +import org.joml.Vector3f; import org.joml.Vector3fc; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.lifecycleEvents.BeforeRemoveComponent; @@ -24,9 +25,6 @@ import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterMode; import org.terasology.entitySystem.systems.RegisterSystem; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import java.util.Iterator; @@ -35,53 +33,6 @@ @RegisterSystem public class Location extends BaseComponentSystem { - /** - * Attaches an entity to another entity. Both must have location components. - * This method sets the child's relative offset and rotation to the parent {@link LocationComponent} - * - * @param parent entity that will be the parent Location to the child - * @param child entity will be attached relative to the parent - * @param offset relative position from parent - * @param relativeRotation relative rotation from parent - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #attachChild(EntityRef, EntityRef, Vector3fc, Quaternionfc, float)}. - */ - @Deprecated - public static void attachChild(EntityRef parent, EntityRef child, Vector3f offset, Quat4f relativeRotation, float relativeScale) { - LocationComponent childLoc = child.getComponent(LocationComponent.class); - LocationComponent parentLoc = parent.getComponent(LocationComponent.class); - if (childLoc != null && parentLoc != null && !childLoc.getParent().equals(parent)) { - LocationComponent oldParentLoc = childLoc.getParent().getComponent(LocationComponent.class); - if (oldParentLoc != null) { - oldParentLoc.children.remove(child); - childLoc.getParent().saveComponent(oldParentLoc); - } - childLoc.parent = parent; - childLoc.setLocalPosition(offset); - childLoc.setLocalRotation(relativeRotation); - childLoc.setLocalScale(relativeScale); - parentLoc.children.add(child); - child.saveComponent(childLoc); - parent.saveComponent(parentLoc); - } - } - - /** - * Attaches an entity to another entity. Both must have location components. - * This method sets the child's relative offset and rotation to the parent {@link LocationComponent} - * - * @param parent entity with a {@link LocationComponent} - * @param child entity with a {@link LocationComponent} attach to the parent - * @param offset relative position from parent - * @param relativeRotation relative rotation from parent - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #attachChild(EntityRef, EntityRef, Vector3fc, Quaternionfc)}. - */ - @Deprecated - public static void attachChild(EntityRef parent, EntityRef child, Vector3f offset, Quat4f relativeRotation) { - attachChild(parent, child, offset, relativeRotation, 1f); - } - /** * Attaches an entity to another entity. Both must have location components. * This method sets the child's relative offset and rotation to the parent {@link LocationComponent} @@ -92,7 +43,7 @@ public static void attachChild(EntityRef parent, EntityRef child, Vector3f offse * @param relativeRotation relative rotation from parent **/ public static void attachChild(EntityRef parent, EntityRef child, Vector3fc offset, Quaternionfc relativeRotation) { - attachChild(parent, child, JomlUtil.from(offset), JomlUtil.from(relativeRotation), 1f); + attachChild(parent, child, offset, relativeRotation, 1f); } /** @@ -106,7 +57,22 @@ public static void attachChild(EntityRef parent, EntityRef child, Vector3fc offs * @param relativeScale relative scale from parent **/ public static void attachChild(EntityRef parent, EntityRef child, Vector3fc offset, Quaternionfc relativeRotation, float relativeScale) { - attachChild(parent, child, JomlUtil.from(offset), JomlUtil.from(relativeRotation), relativeScale); + LocationComponent childLoc = child.getComponent(LocationComponent.class); + LocationComponent parentLoc = parent.getComponent(LocationComponent.class); + if (childLoc != null && parentLoc != null && !childLoc.getParent().equals(parent)) { + LocationComponent oldParentLoc = childLoc.getParent().getComponent(LocationComponent.class); + if (oldParentLoc != null) { + oldParentLoc.children.remove(child); + childLoc.getParent().saveComponent(oldParentLoc); + } + childLoc.parent = parent; + childLoc.setLocalPosition(offset); + childLoc.setLocalRotation(relativeRotation); + childLoc.setLocalScale(relativeScale); + parentLoc.children.add(child); + child.saveComponent(childLoc); + parent.saveComponent(parentLoc); + } } /** @@ -120,7 +86,7 @@ public static void attachChild(EntityRef parent, EntityRef child) { LocationComponent childLoc = child.getComponent(LocationComponent.class); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (childLoc != null && parentLoc != null && !childLoc.getParent().equals(parent)) { - Vector3f oldWorldPos = childLoc.getWorldPosition(); + Vector3f oldWorldPos = childLoc.getWorldPosition(new Vector3f()); LocationComponent oldParentLoc = childLoc.getParent().getComponent(LocationComponent.class); if (oldParentLoc != null) { oldParentLoc.children.remove(child); @@ -138,7 +104,7 @@ public static void removeChild(EntityRef parent, EntityRef child) { LocationComponent childLoc = child.getComponent(LocationComponent.class); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (childLoc != null && parentLoc != null && childLoc.getParent().equals(parent)) { - Vector3f oldWorldPos = childLoc.getWorldPosition(); + Vector3f oldWorldPos = childLoc.getWorldPosition(new Vector3f()); parentLoc.children.remove(child); childLoc.parent = EntityRef.NULL; childLoc.setWorldPosition(oldWorldPos); @@ -157,7 +123,7 @@ public void onDestroyed(BeforeRemoveComponent event, EntityRef entity, LocationC EntityRef child = childIterator.next(); LocationComponent childLoc = child.getComponent(LocationComponent.class); if (childLoc != null) { - Vector3f oldWorldPos = childLoc.getWorldPosition(); + Vector3f oldWorldPos = childLoc.getWorldPosition(new Vector3f()); childLoc.parent = EntityRef.NULL; childLoc.setWorldPosition(oldWorldPos); child.saveComponent(childLoc); @@ -168,8 +134,8 @@ public void onDestroyed(BeforeRemoveComponent event, EntityRef entity, LocationC @ReceiveEvent(netFilter = RegisterMode.REMOTE_CLIENT) public void onResyncLocation(LocationResynchEvent event, EntityRef entityRef, LocationComponent locationComponent) { - locationComponent.setWorldPosition(JomlUtil.from(event.getPosition())); - locationComponent.setWorldRotation(JomlUtil.from(event.getRotation())); + locationComponent.setWorldPosition(event.getPosition()); + locationComponent.setWorldRotation(event.getRotation()); entityRef.saveComponent(locationComponent); } } diff --git a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java index bd1e1105794..931e64846fc 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java @@ -53,15 +53,6 @@ public final class LocationComponent implements Component, ReplicationCheck { public LocationComponent() { } - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #LocationComponent(Vector3fc)}. - */ - @Deprecated - public LocationComponent(Vector3f position) { - setLocalPosition(position); - } - public LocationComponent(Vector3fc position) { setLocalPosition(position); } @@ -75,18 +66,6 @@ public Quat4f getLocalRotation() { return rotation; } - - /** - * @param newQuat - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #setLocalRotation(Quaternionfc)}. - */ - @Deprecated - public void setLocalRotation(Quat4f newQuat) { - lastRotation.set(rotation); - rotation.set(newQuat); - } - /** * set the current local rotation of the component * @@ -97,7 +76,6 @@ public void setLocalRotation(Quaternionfc rot) { rotation.set(JomlUtil.from(rot)); } - /** * @return The position of this component relative to any parent. Can be directly modified to update the component * TODO: make this readonly Vector3fc -- Michael Pollind @@ -106,18 +84,6 @@ public Vector3f getLocalPosition() { return position; } - /** - * @param pos - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #setLocalPosition(Vector3fc)}. - */ - @Deprecated - public void setLocalPosition(Vector3f pos) { - lastPosition.set(position); - position.set(pos); - } - - /** * the local position of this location component * @@ -128,18 +94,6 @@ public void setLocalPosition(Vector3fc pos) { position.set(JomlUtil.from(pos)); } - /** - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getLocalDirection(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getLocalDirection() { - Vector3f result = Direction.FORWARD.getVector3f(); - getLocalRotation().rotate(result, result); - return result; - } - /** * gets the local direction of the given entity in * @@ -150,7 +104,6 @@ public org.joml.Vector3f getLocalDirection(org.joml.Vector3f dest) { return dest.set(Direction.FORWARD.asVector3i()).rotate(JomlUtil.from(getLocalRotation())); } - /** * set the local scale * @param value the scale @@ -167,28 +120,6 @@ public float getLocalScale() { return scale; } - /** - * @return A new vector containing the world location. - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getWorldPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getWorldPosition() { - return getWorldPosition(new Vector3f()); - } - - /** - * @param output - * @return - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getWorldPosition(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getWorldPosition(Vector3f output) { - output.set(JomlUtil.from(getWorldPosition(new org.joml.Vector3f()))); - return output; - } - /** * get the world position * @@ -223,39 +154,8 @@ public void getRelativeTransform(Matrix4f out, EntityRef entity) { out.mul(new Matrix4f().translationRotateScale(JomlUtil.from(position), JomlUtil.from(rotation), scale)); } - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getWorldDirection(org.joml.Vector3f)}. - */ - @Deprecated - public Vector3f getWorldDirection() { - Vector3f result = Direction.FORWARD.getVector3f(); - getWorldRotation().rotate(result, result); - return result; - } - - public org.joml.Vector3f getWorldDirection(org.joml.Vector3f dest) { - return dest.set(Direction.FORWARD.asVector3f()).rotate(JomlUtil.from(getWorldRotation())); - } - - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getWorldRotation(Quaternionf)}. - */ - @Deprecated - public Quat4f getWorldRotation() { - return getWorldRotation(new Quat4f(0, 0, 0, 1)); - } - - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getWorldRotation(Quaternionf)}. - */ - @Deprecated - public Quat4f getWorldRotation(Quat4f output) { - output.set(JomlUtil.from(getWorldRotation(new Quaternionf()))); - return output; + return dest.set(Direction.FORWARD.asVector3f()).rotate(getWorldRotation(new Quaternionf())); } /** @@ -284,16 +184,6 @@ public float getWorldScale() { return result; } - /** - * @param value - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #setWorldPosition(Vector3fc)}. - */ - @Deprecated - public void setWorldPosition(Vector3f value) { - this.setWorldPosition(JomlUtil.from(value)); - } - /** * set the world position of the {@link LocationComponent} * @@ -303,26 +193,14 @@ public void setWorldPosition(Vector3fc pos) { setLocalPosition(pos); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (parentLoc != null) { - this.position.sub(parentLoc.getWorldPosition()); + this.position.sub(JomlUtil.from(parentLoc.getWorldPosition(new org.joml.Vector3f()))); this.position.scale(1f / parentLoc.getWorldScale()); Quat4f rot = new Quat4f(0, 0, 0, 1); - rot.inverse(parentLoc.getWorldRotation()); + rot.inverse(JomlUtil.from(parentLoc.getWorldRotation(new Quaternionf()))); rot.rotate(this.position, this.position); } } - /** - * set the world rotation of the {@link LocationComponent} - * - * @param value - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #setWorldRotation(Quaternionfc)}. - */ - @Deprecated - public void setWorldRotation(Quat4f value) { - this.setWorldRotation(JomlUtil.from(value)); - } - /** * set the world rotation of the {@link LocationComponent} * @@ -332,7 +210,7 @@ public void setWorldRotation(Quaternionfc value) { setLocalRotation(value); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (parentLoc != null) { - Quat4f worldRot = parentLoc.getWorldRotation(); + Quat4f worldRot = JomlUtil.from(parentLoc.getWorldRotation(new Quaternionf())); worldRot.inverse(); this.rotation.mul(worldRot, this.rotation); } diff --git a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java index 3eea14ee23d..c9c79b429c3 100644 --- a/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java +++ b/engine/src/main/java/org/terasology/logic/players/LocalPlayer.java @@ -13,6 +13,7 @@ import org.terasology.logic.characters.events.ActivationRequest; import org.terasology.logic.location.LocationComponent; import org.terasology.math.Direction; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Quat4f; import org.terasology.network.ClientComponent; import org.terasology.physics.HitResult; @@ -113,11 +114,7 @@ public Vector3f getPosition(Vector3f dest) { */ @Deprecated public Quat4f getRotation() { - LocationComponent location = getCharacterEntity().getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition(new Vector3f()).x)) { - return new Quat4f(Quat4f.IDENTITY); - } - return location.getWorldRotation(); + return JomlUtil.from(getRotation(new Quaternionf())); } /** @@ -166,16 +163,7 @@ public Vector3f getViewPosition(Vector3f dest) { */ @Deprecated public Quat4f getViewRotation() { - ClientComponent clientComponent = getClientEntity().getComponent(ClientComponent.class); - if (clientComponent == null) { - return new Quat4f(Quat4f.IDENTITY); - } - LocationComponent location = clientComponent.camera.getComponent(LocationComponent.class); - if (location == null || Float.isNaN(location.getWorldPosition(new Vector3f()).x)) { - return getRotation(); - } - - return location.getWorldRotation(); + return JomlUtil.from(getViewRotation(new Quaternionf())); } /** diff --git a/engine/src/main/java/org/terasology/world/block/BlockComponent.java b/engine/src/main/java/org/terasology/world/block/BlockComponent.java index a40f15ad321..4ddbb238a22 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockComponent.java +++ b/engine/src/main/java/org/terasology/world/block/BlockComponent.java @@ -33,7 +33,7 @@ public BlockComponent() { } /** * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #BlockComponent(Block, org.joml.Vector3i)}. + * {@link #BlockComponent(Block, org.joml.Vector3ic)}. */ @Deprecated public BlockComponent(Block block, Vector3i pos) { @@ -41,7 +41,7 @@ public BlockComponent(Block block, Vector3i pos) { this.position.set(pos); } - public BlockComponent(Block block, org.joml.Vector3i pos) { + public BlockComponent(Block block, org.joml.Vector3ic pos) { this.block = block; this.position.set(JomlUtil.from(pos)); } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index 6c478700be6..5841dec0987 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -265,7 +265,7 @@ public EntityRef getBlockEntityAt(Vector3ic blockPosition) { EntityRef blockEntity = getExistingBlockEntityAt(blockPosition); if ((!blockEntity.exists() || !blockEntity.hasComponent(NetworkComponent.class)) && isBlockRelevant(blockPosition.x(), blockPosition.y(), blockPosition.z())) { Block block = getBlock(blockPosition.x(), blockPosition.y(), blockPosition.z()); - blockEntity = createBlockEntity(JomlUtil.from(blockPosition), block); + blockEntity = createBlockEntity(blockPosition, block); } return blockEntity; } @@ -375,9 +375,9 @@ private void updateComponent(EntityRef blockEntity, Compon } } - private EntityRef createBlockEntity(Vector3i blockPosition, Block block) { + private EntityRef createBlockEntity(Vector3ic blockPosition, Block block) { EntityBuilder builder = entityManager.newBuilder(block.getPrefab().orElse(null)); - builder.addComponent(new LocationComponent(blockPosition.toVector3f())); + builder.addComponent(new LocationComponent(new org.joml.Vector3f(blockPosition))); builder.addComponent(new BlockComponent(block, blockPosition)); boolean isTemporary = isTemporaryBlock(builder, block); if (!isTemporary && !builder.hasComponent(NetworkComponent.class)) { @@ -392,7 +392,7 @@ private EntityRef createBlockEntity(Vector3i blockPosition, Block block) { blockEntity = builder.build(); } - blockEntityLookup.put(new Vector3i(blockPosition), blockEntity); + blockEntityLookup.put(JomlUtil.from(blockPosition), blockEntity); return blockEntity; } From c2cdbdd52c83cd6cdb6831230072993174254e98 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 12:17:18 -0800 Subject: [PATCH 173/259] doc(build): document ValidateZipDistribution class --- .../main/kotlin/terasology-dist.gradle.kts | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts index 36bd9bd406d..b06ba3cf58a 100644 --- a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts @@ -1,13 +1,31 @@ // Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +/** + * Make assertions about the content of a zip file. + * + * Do make sure you put any inspection of the file in the task's *execution phase,* not in its *configuration.* + * i.e. use a `doLast` block. + * + * TODO: Produce proper test output instead of just throwing an exception and failing the build. + * Probably with [TestKit](https://docs.gradle.org/current/userguide/test_kit.html)? + */ @Suppress("UnstableApiUsage") open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : DefaultTask() { + + /** + * The zip file to inspect. + * + * @see fromTask to set this to the output of a Zip task. + */ @InputFile val zipFile: RegularFileProperty = objects.fileProperty() + /** + * A tree view of the content of the zip file. + */ @get:Internal - val tree by lazy { + val tree: FileTree by lazy { zipFile.finalizeValue() project.zipTree(zipFile) } @@ -17,23 +35,39 @@ open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : } @TaskAction - fun checkZip() { + private fun checkZip() { zipFile.finalizeValueOnRead() } + /** + * Use zip file output by the given task. + */ fun fromTask(taskProvider: Provider) { zipFile.set(taskProvider.flatMap { it.archiveFile }) } + /** + * Assert two objects are equal. + * + * @see kotlin.test.assertEquals + */ fun assertEquals(expected: Any, actual: Any, message: String? = null) = kotlin.test.assertEquals(expected, actual, message) + /** + * Fail this test with the given message. + */ fun fail(message: String): Nothing = kotlin.test.fail(message) - fun assertContainsPath(expected: String) { + /** + * Assert the zip contains exactly one match for the given pattern. + * + * @param pattern: match pattern in glob-style [pattern format](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/util/PatternFilterable.html). + */ + fun assertContainsPath(pattern: String) { assertEquals(1, tree.matching { - include(expected) - }.count(), "Matches for $expected") + include(pattern) + }.count(), "Matches for $pattern") } } From 5616d322170faf898ff1ecb03037478fe49ec5c5 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 15:02:41 -0800 Subject: [PATCH 174/259] build(PC): rename `modules` config to `serverModules` This is likely something to revisit but for now it helps me avoid accidentally messing with the server config. --- facades/PC/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 0bc1b729c14..8e3f58a101d 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -82,7 +82,7 @@ logger.info("PC VERSION: {}", version) group = "org.terasology.facades" configurations { - register("modules") { + register("serverModules") { description = "for fetching modules for running a server" isTransitive = false } @@ -180,12 +180,12 @@ tasks.register("setupServerModules") { it.splitToSequence(",").forEach { logger.info("Extra module: {}", it) dependencies { - "modules"(group = "org.terasology.modules", name = it, version = "+") + "serverModules"(group = "org.terasology.modules", name = it, version = "+") } } } - from(configurations.named("modules")) + from(configurations.named("serverModules")) into(File(rootProject.file(localServerDataPath), "modules")) } From f9afdf684779ad23a3572121433901ddfa87e129 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 17:47:06 -0800 Subject: [PATCH 175/259] build(facade): refactor JavaExec.commonConfigure to buildSrc It seems as if I want to import functions, they must in .kt and not .gradle.kts? --- .../kotlin/org/terasology/gradology/exec.kt | 62 +++++++++++++++++++ facades/PC/build.gradle.kts | 51 +-------------- 2 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt new file mode 100644 index 00000000000..f55dcc20c03 --- /dev/null +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -0,0 +1,62 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.gradology + +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.plugins.JavaApplication +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.the + +val logger: Logger = Logging.getLogger("org.tersology.gradology") + +/** + * The subdirectory for this development environment. + * + * Only use this to run local processes. When building releases, you will be targeting other + * operating systems in addition to your own. + * + * @return + */ +fun nativeSubdirectoryName(): String { + return when { + Os.isFamily(Os.FAMILY_WINDOWS) -> "windows" + Os.isFamily(Os.FAMILY_MAC) -> "macosx" + Os.isFamily(Os.FAMILY_UNIX) -> "linux" + else -> { + logger.warn("What kind of libraries do you use on this? {}", System.getProperty("os.name")) + "UNKNOWN" + } + } +} + + +fun isMacOS() : Boolean { + return Os.isFamily(Os.FAMILY_MAC) +} + + +// Used for all game configs. +fun JavaExec.commonConfigure() { + group = "terasology run" + + dependsOn(":extractNatives") + dependsOn("classes") + + mainClass.set(project.the().mainClass) + workingDir = project.rootDir + + classpath(project.the()["main"].runtimeClasspath) + + args("-homedir") + jvmArgs("-Xmx3072m") + + if (isMacOS()) { + args("-noSplash") + jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true") + } +} diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 8e3f58a101d..a90dd383913 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -5,7 +5,8 @@ import Terasology_dist_gradle.ValidateZipDistribution import org.apache.tools.ant.filters.FixCrLfFilter -import org.apache.tools.ant.taskdefs.condition.Os +import org.terasology.gradology.commonConfigure +import org.terasology.gradology.nativeSubdirectoryName import java.text.SimpleDateFormat import java.util.* @@ -20,32 +21,6 @@ apply(from = "$rootDir/config/gradle/publish.gradle") val dateTimeFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX") dateTimeFormat.timeZone = TimeZone.getTimeZone("UTC") - -/** - * The subdirectory for this development environment. - * - * Only use this to run local processes. When building releases, you will be targeting other - * operating systems in addition to your own. - * - * @return - */ -fun nativeSubdirectoryName(): String { - return when { - Os.isFamily(Os.FAMILY_WINDOWS) -> "windows" - Os.isFamily(Os.FAMILY_MAC) -> "macosx" - Os.isFamily(Os.FAMILY_UNIX) -> "linux" - else -> { - logger.warn("What kind of libraries do you use on this? {}", System.getProperty("os.name")) - "UNKNOWN" - } - } -} - -fun isMacOS() : Boolean { - return Os.isFamily(Os.FAMILY_MAC) -} - - // Default path to store server data if running headless via Gradle val localServerDataPath by extra("terasology-server") @@ -111,28 +86,6 @@ dependencies { * Run Targets */ -// Used for all game configs. -fun JavaExec.commonConfigure() { - group = "terasology run" - - dependsOn(":extractNatives") - dependsOn("classes") - - // Run arguments - main = mainClassName - workingDir = rootDir - - classpath(sourceSets["main"].runtimeClasspath) - - args("-homedir") - jvmArgs("-Xmx3072m") - - if (isMacOS()) { - args("-noSplash") - jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true") - } -} - tasks.register("game") { commonConfigure() description = "Run 'Terasology' to play the game as a standard PC application" From ccaa920b6ea010aafa1c508098e6a8ec6368d0b7 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 18:58:18 -0800 Subject: [PATCH 176/259] build(PC): refactor commonConfigure function to a RunTerasology task class --- .../kotlin/org/terasology/gradology/exec.kt | 32 +++++++++++-------- facades/PC/build.gradle.kts | 17 ++++------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index f55dcc20c03..c9b6ac43fc5 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -40,23 +40,29 @@ fun isMacOS() : Boolean { } -// Used for all game configs. -fun JavaExec.commonConfigure() { - group = "terasology run" +open class RunTerasology : JavaExec() { - dependsOn(":extractNatives") - dependsOn("classes") + init { + group = "terasology run" - mainClass.set(project.the().mainClass) - workingDir = project.rootDir + mainClass.set(project.the().mainClass) + workingDir = project.rootDir - classpath(project.the()["main"].runtimeClasspath) + initConfig() + } + + private fun initConfig() { + dependsOn(":extractNatives") + dependsOn("classes") - args("-homedir") - jvmArgs("-Xmx3072m") + classpath(project.the()["main"].runtimeClasspath) - if (isMacOS()) { - args("-noSplash") - jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true") + args("-homedir") + jvmArgs("-Xmx3072m") + + if (isMacOS()) { + args("-noSplash") + jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true") + } } } diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index a90dd383913..34b5e4d4e66 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -5,7 +5,7 @@ import Terasology_dist_gradle.ValidateZipDistribution import org.apache.tools.ant.filters.FixCrLfFilter -import org.terasology.gradology.commonConfigure +import org.terasology.gradology.RunTerasology import org.terasology.gradology.nativeSubdirectoryName import java.text.SimpleDateFormat import java.util.* @@ -86,8 +86,7 @@ dependencies { * Run Targets */ -tasks.register("game") { - commonConfigure() +tasks.register("game") { description = "Run 'Terasology' to play the game as a standard PC application" // If there are no actual source modules let the user know, just in case .. @@ -96,20 +95,17 @@ tasks.register("game") { } } -tasks.register("profile") { - commonConfigure() +tasks.register("profile") { description = "Run 'Terasology' to play the game as a standard PC application (with Java FlightRecorder profiling)" jvmArgs( "-XX:+UnlockCommercialFeatures", "-XX:+FlightRecorder", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints", "-XX:StartFlightRecording=filename=terasology.jfr,dumponexit=true") } -tasks.register("debug") { - commonConfigure() +tasks.register("debug") { description = "Run 'Terasology' to play the game as a standard PC application (in debug mode)" jvmArgs( "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044") } -tasks.register("permissiveNatives") { - commonConfigure() +tasks.register("permissiveNatives") { description = "Run 'Terasology' with security set to permissive and natives loading a second way (for KComputers)" args("-permissiveSecurity") @@ -143,8 +139,7 @@ tasks.register("setupServerModules") { } // TODO: Make a task to reset server / game data -tasks.register("server") { - commonConfigure() +tasks.register("server") { description = "Starts a headless multiplayer server with data stored in [project-root]/$localServerDataPath" dependsOn("setupServerConfig") dependsOn("setupServerModules") From 8482b339754c960ee285fe2e44ef4c51c14718c1 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 19:06:05 -0800 Subject: [PATCH 177/259] build(PC): refactor "natives" dependency to facade plugin --- buildSrc/src/main/kotlin/facade.gradle.kts | 18 ++++++++++++++++++ .../kotlin/org/terasology/gradology/exec.kt | 4 +--- facades/PC/build.gradle.kts | 6 +----- 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 buildSrc/src/main/kotlin/facade.gradle.kts diff --git a/buildSrc/src/main/kotlin/facade.gradle.kts b/buildSrc/src/main/kotlin/facade.gradle.kts new file mode 100644 index 00000000000..172b08435d3 --- /dev/null +++ b/buildSrc/src/main/kotlin/facade.gradle.kts @@ -0,0 +1,18 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +plugins { + application +} + +val dirNatives: String by rootProject.extra + +configurations { + register("natives") { + description = "native libraries (.dll and .so)" + } +} + +dependencies { + "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) +} diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index c9b6ac43fc5..b8fb6fe64e9 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -52,9 +52,7 @@ open class RunTerasology : JavaExec() { } private fun initConfig() { - dependsOn(":extractNatives") - dependsOn("classes") - + dependsOn(project.configurations["natives"]) classpath(project.the()["main"].runtimeClasspath) args("-homedir") diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 34b5e4d4e66..b4009bdd70a 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -13,6 +13,7 @@ import java.util.* plugins { application `terasology-dist` + facade } // Grab all the common stuff like plugins to use, artifact repositories, code analysis config @@ -61,9 +62,6 @@ configurations { description = "for fetching modules for running a server" isTransitive = false } - register("natives") { - description = "native libraries (.dll and .so)" - } } dependencies { @@ -74,8 +72,6 @@ dependencies { // TODO: Consider whether we can move the CR dependency back here from the engine, where it is referenced from the main menu implementation(group = "org.terasology.crashreporter", name = "cr-terasology", version = "4.1.0") - "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) - // Make sure any local module builds are up-to-date and have their dependencies by declaring // a runtime dependency on whatever the `:modules` subproject declares. // This won't add anything if there are no modules checked out. From 3254d522a33c5e5ec382528e773657e09e0555c4 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sun, 31 Jan 2021 21:50:44 -0800 Subject: [PATCH 178/259] build(PC): put dependency modules in moduleCache/ This is a good proof of concept for how to get Gradle to provide module dependencies, but IntelliJ might be blind to them. --- buildSrc/src/main/kotlin/facade.gradle.kts | 30 +++++++++++++++++++ .../kotlin/org/terasology/gradology/exec.kt | 1 + .../terasology/engine/paths/PathManager.java | 15 ++++++---- facades/PC/build.gradle.kts | 5 ---- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/facade.gradle.kts b/buildSrc/src/main/kotlin/facade.gradle.kts index 172b08435d3..9896dd4ba1d 100644 --- a/buildSrc/src/main/kotlin/facade.gradle.kts +++ b/buildSrc/src/main/kotlin/facade.gradle.kts @@ -11,8 +11,38 @@ configurations { register("natives") { description = "native libraries (.dll and .so)" } + register("modules") { + description = "locally built modules and their dependencies" + + resolutionStrategy { + preferProjectModules() + } + + @Suppress("UnstableApiUsage") + shouldResolveConsistentlyWith(configurations["runtimeClasspath"]) + } } dependencies { "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) + + // Make sure any local module builds are up-to-date and have their dependencies by declaring + // a runtime dependency on whatever the `:modules` subproject declares. + // This won't add anything if there are no modules checked out. + "modules"(platform(project(":modules"))) +} + +tasks.register("provideModuleDependencies") { + dependsOn(configurations["modules"]) + + destinationDir = rootProject.file("moduleCache") + + from(configurations["modules"].resolvedConfiguration.resolvedArtifacts.mapNotNull { + if ( + (it.moduleVersion.id.group == "org.terasology.modules") and + // FIXME: There must be a better way to filter out things from local projects than + // doing string comparisons on the display name. + (!it.id.componentIdentifier.toString().startsWith("project ")) + ) it.file else null + }) } diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index b8fb6fe64e9..f08380d5b99 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -54,6 +54,7 @@ open class RunTerasology : JavaExec() { private fun initConfig() { dependsOn(project.configurations["natives"]) classpath(project.the()["main"].runtimeClasspath) + dependsOn("provideModuleDependencies") args("-homedir") jvmArgs("-Xmx3072m") diff --git a/engine/src/main/java/org/terasology/engine/paths/PathManager.java b/engine/src/main/java/org/terasology/engine/paths/PathManager.java index 12a6ff57098..27d3f39861f 100644 --- a/engine/src/main/java/org/terasology/engine/paths/PathManager.java +++ b/engine/src/main/java/org/terasology/engine/paths/PathManager.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.paths; @@ -33,6 +33,7 @@ public final class PathManager { private static final String LOG_DIR = "logs"; private static final String SHADER_LOG_DIR = "shaders"; private static final String MOD_DIR = "modules"; + private static final String MOD_CACHE_DIR = "moduleCache"; private static final String SCREENSHOT_DIR = "screenshots"; private static final String NATIVES_DIR = "natives"; private static final String CONFIGS_DIR = "configs"; @@ -303,12 +304,14 @@ private void updateDirs() throws IOException { Files.createDirectories(shaderLogPath); Path homeModPath = homePath.resolve(MOD_DIR); Files.createDirectories(homeModPath); - Path installModPath = installPath.resolve(MOD_DIR); - Files.createDirectories(installModPath); - if (Files.isSameFile(homeModPath, installModPath)) { - modPaths = ImmutableList.of(homeModPath); + Path modCachePath = homePath.resolve(MOD_CACHE_DIR); + Files.createDirectories(modCachePath); + if (Files.isSameFile(homePath, installPath)) { + modPaths = ImmutableList.of(modCachePath, homeModPath); } else { - modPaths = ImmutableList.of(installModPath, homeModPath); + Path installModPath = installPath.resolve(MOD_DIR); + Files.createDirectories(installModPath); + modPaths = ImmutableList.of(installModPath, modCachePath, homeModPath); } screenshotPath = homePath.resolve(SCREENSHOT_DIR); Files.createDirectories(screenshotPath); diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index b4009bdd70a..f308f7198de 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -71,11 +71,6 @@ dependencies { // TODO: Consider whether we can move the CR dependency back here from the engine, where it is referenced from the main menu implementation(group = "org.terasology.crashreporter", name = "cr-terasology", version = "4.1.0") - - // Make sure any local module builds are up-to-date and have their dependencies by declaring - // a runtime dependency on whatever the `:modules` subproject declares. - // This won't add anything if there are no modules checked out. - runtimeOnly(platform(project(":modules"))) } /**************************************** From 6bf03eec8caa81fb4c2490f197a1a0ca6221b049 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Mon, 1 Feb 2021 19:13:58 +0100 Subject: [PATCH 179/259] feat(JOML): migrate rest of `LocationComponent` (#4445) Co-authored-by: Michael Pollind --- .../logic/location/LocationComponentTest.java | 15 ++-- .../terasology/logic/ai/SimpleAISystem.java | 3 +- .../characters/CharacterSoundSystem.java | 2 +- .../logic/location/LocationChangedEvent.java | 50 ++++++------- .../logic/location/LocationChangedSystem.java | 7 +- .../logic/location/LocationComponent.java | 73 ++++++++++--------- .../logic/players/CameraClientSystem.java | 2 +- 7 files changed, 76 insertions(+), 76 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java b/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java index 6cc673a30d4..7d3e88fd978 100644 --- a/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java +++ b/engine-tests/src/test/java/org/terasology/logic/location/LocationComponentTest.java @@ -22,14 +22,13 @@ import org.terasology.TerasologyTestingEnvironment; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.entity.lifecycleEvents.BeforeRemoveComponent; -import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.terasology.joml.test.VectorAssert.assertEquals; import static org.terasology.joml.test.QuaternionAssert.assertEquals; +import static org.terasology.joml.test.VectorAssert.assertEquals; /** @@ -67,19 +66,19 @@ private EntityRef createFakeEntityWith(LocationComponent locationComponent) { @Test public void testSetLocalPosition() { loc.setLocalPosition(pos1); - assertEquals(pos1, JomlUtil.from(loc.getLocalPosition())); + assertEquals(pos1, loc.getLocalPosition()); } @Test public void testSetLocalRotation() { loc.setLocalRotation(yawRotation); - assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); + assertEquals(yawRotation,loc.getLocalRotation(), 0.0001f); } @Test public void testUnparentedWorldLocationSameAsLocal() { loc.setLocalPosition(pos1); - assertEquals(JomlUtil.from(loc.getLocalPosition()), loc.getWorldPosition(new Vector3f())); + assertEquals(loc.getLocalPosition(), loc.getWorldPosition(new Vector3f())); } @Test @@ -121,7 +120,7 @@ public void testScaleRotateAndOffsetCombineCorrectlyForWorldPosition() { @Test public void testWorldRotationSameAsLocalRotationWhenNoParent() { loc.setLocalRotation(yawRotation); - assertEquals(JomlUtil.from(loc.getLocalRotation()), loc.getWorldRotation(new Quaternionf())); + assertEquals(loc.getLocalRotation(), loc.getWorldRotation(new Quaternionf()), 0.00001f); } @Test @@ -157,7 +156,7 @@ public void testSetWorldPositionWorksWithOffsetParent() { LocationComponent parent = giveParent(); parent.setLocalPosition(pos1); loc.setWorldPosition(pos1plus2); - assertEquals(pos2, JomlUtil.from(loc.getLocalPosition()), 0.0001f); + assertEquals(pos2, loc.getLocalPosition(), 0.0001f); assertEquals(pos1plus2, loc.getWorldPosition(new Vector3f())); } @@ -230,7 +229,7 @@ public void testSetWorldScaleWorksWithScaledParent() { public void testSetWorldRotationWorksWithNoParent() { loc.setWorldRotation(yawRotation); assertEquals(yawRotation, loc.getWorldRotation(new Quaternionf()), 0.0001f); - assertEquals(yawRotation, JomlUtil.from(loc.getLocalRotation()), 0.0001f); + assertEquals(yawRotation, loc.getLocalRotation(), 0.0001f); } @Test diff --git a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java index 94f274a8684..5afe1b25673 100644 --- a/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java +++ b/engine/src/main/java/org/terasology/logic/ai/SimpleAISystem.java @@ -15,6 +15,7 @@ */ package org.terasology.logic.ai; +import org.joml.Quaternionf; import org.joml.Vector3f; import org.terasology.engine.Time; import org.terasology.entitySystem.entity.EntityManager; @@ -88,7 +89,7 @@ public void update(float delta) { drive.set(targetDirection); float yaw = (float) Math.atan2(targetDirection.x, targetDirection.z); - location.getLocalRotation().set(0, 1, 0, yaw); + location.setLocalRotation(new Quaternionf().setAngleAxis(yaw, 0, 1, 0)); entity.saveComponent(location); } entity.send(new CharacterMoveInputEvent(0, 0, 0, drive, false, false, false, time.getGameDeltaInMs())); diff --git a/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java b/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java index 0566bfc8c41..de26295aff7 100644 --- a/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java +++ b/engine/src/main/java/org/terasology/logic/characters/CharacterSoundSystem.java @@ -71,7 +71,7 @@ public void onFootstep(FootstepEvent event, EntityRef entity, LocationComponent List footstepSounds = characterSounds.footstepSounds; // Check if the block the character is standing on has footstep sounds - Vector3i blockPos = new Vector3i(JomlUtil.from(locationComponent.getLocalPosition()), RoundingMode.FLOOR); + Vector3i blockPos = new Vector3i(locationComponent.getLocalPosition(), RoundingMode.FLOOR); blockPos.y--; // The block *below* the character's feet is interesting to us Block block = worldProvider.getBlock(blockPos); if (block != null) { diff --git a/engine/src/main/java/org/terasology/logic/location/LocationChangedEvent.java b/engine/src/main/java/org/terasology/logic/location/LocationChangedEvent.java index e74e66eace0..71f5c7dfe9e 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationChangedEvent.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationChangedEvent.java @@ -15,19 +15,18 @@ */ package org.terasology.logic.location; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector3f; +import org.joml.Vector3fc; import org.terasology.entitySystem.event.Event; -import org.terasology.math.geom.BaseVector3f; -import org.terasology.math.geom.ImmutableQuat4f; -import org.terasology.math.geom.ImmutableVector3f; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; public class LocationChangedEvent implements Event { public final LocationComponent component; - public final ImmutableVector3f oldPosition; - public final ImmutableQuat4f oldRotation; - public final ImmutableVector3f newPosition; - public final ImmutableQuat4f newRotation; + public final Vector3fc oldPosition; + public final Quaternionfc oldRotation; + public final Vector3fc newPosition; + public final Quaternionfc newRotation; public LocationChangedEvent(LocationComponent newLocation) { this(newLocation, newLocation.position, newLocation.rotation, newLocation.position, newLocation.rotation); @@ -41,43 +40,42 @@ public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, V this(newLocation, oPosition, newLocation.rotation, nPosition, newLocation.rotation); } - public LocationChangedEvent(LocationComponent newLocation, Quat4f oRotation) { + public LocationChangedEvent(LocationComponent newLocation, Quaternionfc oRotation) { this(newLocation, newLocation.position, oRotation, newLocation.position, newLocation.rotation); } - public LocationChangedEvent(LocationComponent newLocation, Quat4f oRotation, Quat4f nRotation) { + public LocationChangedEvent(LocationComponent newLocation, Quaternionfc oRotation, Quaternionfc nRotation) { this(newLocation, newLocation.position, oRotation, newLocation.position, nRotation); } - public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quat4f oRotation) { + public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation) { this(newLocation, oPosition, oRotation, newLocation.position, newLocation.rotation); } - public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quat4f oRotation, Vector3f nPosition) { + public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation, + Vector3f nPosition) { this(newLocation, oPosition, oRotation, nPosition, newLocation.rotation); } - public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quat4f oRotation, Quat4f nRotation) - { + public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation, + Quaternionfc nRotation) { this(newLocation, oPosition, oRotation, newLocation.position, nRotation); } - public LocationChangedEvent(LocationComponent nComponent, Vector3f oPosition, Quat4f oRotation, Vector3f nPosition, Quat4f nRotation) - { - oldPosition = ImmutableVector3f.createOrUse(oPosition); - oldRotation = new ImmutableQuat4f(oRotation.x, oRotation.y, oRotation.z, oRotation.w); - newPosition = ImmutableVector3f.createOrUse(nPosition); - newRotation = new ImmutableQuat4f(nRotation.x, nRotation.y, nRotation.z, nRotation.w);; + public LocationChangedEvent(LocationComponent nComponent, Vector3fc oPosition, Quaternionfc oRotation, + Vector3fc nPosition, Quaternionfc nRotation) { + oldPosition = new Vector3f(oPosition); + oldRotation = new Quaternionf(oRotation); + newPosition = new Vector3f(nPosition); + newRotation = new Quaternionf(nRotation); component = nComponent; } - public BaseVector3f vectorMoved() - { - return oldPosition != null ? newPosition.sub(oldPosition) : Vector3f.zero(); + public Vector3f vectorMoved(Vector3f dest) { + return oldPosition != null ? newPosition.sub(oldPosition, dest) : dest.set(0, 0, 0); } - public float distanceMoved() - { + public float distanceMoved() { return oldPosition != null ? newPosition.distance(oldPosition) : 0.0F; } } diff --git a/engine/src/main/java/org/terasology/logic/location/LocationChangedSystem.java b/engine/src/main/java/org/terasology/logic/location/LocationChangedSystem.java index 25c728476a8..77f8e74b431 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationChangedSystem.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationChangedSystem.java @@ -24,12 +24,11 @@ @RegisterSystem(RegisterMode.AUTHORITY) public class LocationChangedSystem extends BaseComponentSystem { + @ReceiveEvent(components = {LocationComponent.class}) - public void onItemUpdate(OnChangedComponent event, EntityRef entity) - { + public void onItemUpdate(OnChangedComponent event, EntityRef entity) { LocationComponent lc = entity.getComponent(LocationComponent.class); - if (!lc.lastPosition.equals(lc.position) || !lc.lastRotation.equals(lc.rotation)) - { + if (!lc.lastPosition.equals(lc.position) || !lc.lastRotation.equals(lc.rotation)) { entity.send(new LocationChangedEvent(lc, lc.lastPosition, lc.lastRotation)); lc.lastPosition.set(lc.position); lc.lastRotation.set(lc.rotation); diff --git a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java index 931e64846fc..231b5237ab2 100644 --- a/engine/src/main/java/org/terasology/logic/location/LocationComponent.java +++ b/engine/src/main/java/org/terasology/logic/location/LocationComponent.java @@ -6,13 +6,11 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Quaternionfc; +import org.joml.Vector3f; import org.joml.Vector3fc; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.Direction; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.network.Replicate; import org.terasology.network.ReplicationCheck; import org.terasology.nui.properties.TextField; @@ -24,7 +22,6 @@ /** * Component represent the location and facing of an entity in the world - * */ public final class LocationComponent implements Component, ReplicationCheck { @@ -42,13 +39,13 @@ public final class LocationComponent implements Component, ReplicationCheck { @TextField Vector3f position = new Vector3f(); @Replicate - Quat4f rotation = new Quat4f(0, 0, 0, 1); + Quaternionf rotation = new Quaternionf(); @Replicate float scale = 1.0f; @Replicate Vector3f lastPosition = new Vector3f(); @Replicate - Quat4f lastRotation = new Quat4f(0, 0, 0, 1); + Quaternionf lastRotation = new Quaternionf(); public LocationComponent() { } @@ -59,10 +56,8 @@ public LocationComponent(Vector3fc position) { /** * @return local rotation of location component - * - * TODO: make this readonly Quaternionfc -- Michael Pollind */ - public Quat4f getLocalRotation() { + public Quaternionfc getLocalRotation() { return rotation; } @@ -72,15 +67,18 @@ public Quat4f getLocalRotation() { * @param rot local rotation */ public void setLocalRotation(Quaternionfc rot) { + this.setLocalRotation(rot.x(), rot.y(), rot.z(), rot.w()); + } + + public void setLocalRotation(float x, float y, float z, float w) { lastRotation.set(rotation); - rotation.set(JomlUtil.from(rot)); + rotation.set(x, y, z, w); } /** * @return The position of this component relative to any parent. Can be directly modified to update the component - * TODO: make this readonly Vector3fc -- Michael Pollind */ - public Vector3f getLocalPosition() { + public Vector3fc getLocalPosition() { return position; } @@ -90,8 +88,12 @@ public Vector3f getLocalPosition() { * @param pos position to set */ public void setLocalPosition(Vector3fc pos) { + setLocalPosition(pos.x(), pos.y(), pos.z()); + } + + public void setLocalPosition(float x, float y, float z) { lastPosition.set(position); - position.set(JomlUtil.from(pos)); + position.set(x, y, z); } /** @@ -100,12 +102,13 @@ public void setLocalPosition(Vector3fc pos) { * @param dest will hold the result * @return dest */ - public org.joml.Vector3f getLocalDirection(org.joml.Vector3f dest) { - return dest.set(Direction.FORWARD.asVector3i()).rotate(JomlUtil.from(getLocalRotation())); + public Vector3f getLocalDirection(Vector3f dest) { + return dest.set(Direction.FORWARD.asVector3i()).rotate(getLocalRotation()); } /** * set the local scale + * * @param value the scale */ public void setLocalScale(float value) { @@ -114,6 +117,7 @@ public void setLocalScale(float value) { /** * local scale + * * @return the scale */ public float getLocalScale() { @@ -126,21 +130,22 @@ public float getLocalScale() { * @param dest will hold the result * @return dest */ - public org.joml.Vector3f getWorldPosition(org.joml.Vector3f dest) { - dest.set(JomlUtil.from(position)); + public Vector3f getWorldPosition(Vector3f dest) { + dest.set(position); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); while (parentLoc != null) { - dest.mul(parentLoc.scale); - dest.rotate(JomlUtil.from(parentLoc.getLocalRotation())); - dest.add(JomlUtil.from(parentLoc.position)); + dest.mul(parentLoc.scale) + .rotate(parentLoc.getLocalRotation()) + .add(parentLoc.position); parentLoc = parentLoc.parent.getComponent(LocationComponent.class); } return dest; } /** - * Populates out with the transform of this entity relative to the given entity, or the world transform if entity - * is not in this entity's parent hierarchy + * Populates out with the transform of this entity relative to the given entity, or the world transform if entity is + * not in this entity's parent hierarchy + * * @param out * @param entity */ @@ -151,10 +156,10 @@ public void getRelativeTransform(Matrix4f out, EntityRef entity) { loc.getRelativeTransform(out, entity); } } - out.mul(new Matrix4f().translationRotateScale(JomlUtil.from(position), JomlUtil.from(rotation), scale)); + out.mul(new Matrix4f().translationRotateScale(position, rotation, scale)); } - public org.joml.Vector3f getWorldDirection(org.joml.Vector3f dest) { + public Vector3f getWorldDirection(Vector3f dest) { return dest.set(Direction.FORWARD.asVector3f()).rotate(getWorldRotation(new Quaternionf())); } @@ -165,10 +170,10 @@ public org.joml.Vector3f getWorldDirection(org.joml.Vector3f dest) { * @return dest */ public Quaternionf getWorldRotation(Quaternionf dest) { - dest.set(JomlUtil.from(rotation)); + dest.set(rotation); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); while (parentLoc != null) { - dest.premul(JomlUtil.from(parentLoc.rotation)); + dest.premul(parentLoc.rotation); parentLoc = parentLoc.parent.getComponent(LocationComponent.class); } return dest; @@ -193,11 +198,9 @@ public void setWorldPosition(Vector3fc pos) { setLocalPosition(pos); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (parentLoc != null) { - this.position.sub(JomlUtil.from(parentLoc.getWorldPosition(new org.joml.Vector3f()))); - this.position.scale(1f / parentLoc.getWorldScale()); - Quat4f rot = new Quat4f(0, 0, 0, 1); - rot.inverse(JomlUtil.from(parentLoc.getWorldRotation(new Quaternionf()))); - rot.rotate(this.position, this.position); + this.position.sub(parentLoc.getWorldPosition(new Vector3f())); + this.position.div(parentLoc.getWorldScale()); + this.position.rotate(parentLoc.getWorldRotation(new Quaternionf()).conjugate()); } } @@ -210,9 +213,8 @@ public void setWorldRotation(Quaternionfc value) { setLocalRotation(value); LocationComponent parentLoc = parent.getComponent(LocationComponent.class); if (parentLoc != null) { - Quat4f worldRot = JomlUtil.from(parentLoc.getWorldRotation(new Quaternionf())); - worldRot.inverse(); - this.rotation.mul(worldRot, this.rotation); + Quaternionf worldRot = parentLoc.getWorldRotation(new Quaternionf()).conjugate(); + this.rotation.premul(worldRot); } } @@ -239,7 +241,8 @@ public boolean equals(Object o) { } if (o instanceof LocationComponent) { LocationComponent other = (LocationComponent) o; - return other.scale == scale && Objects.equals(parent, other.parent) && Objects.equals(position, other.position) && Objects.equals(rotation, other.rotation); + return other.scale == scale && Objects.equals(parent, other.parent) && Objects.equals(position, + other.position) && Objects.equals(rotation, other.rotation); } return false; } diff --git a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java index 0733c73d928..1218ef66ad0 100644 --- a/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java +++ b/engine/src/main/java/org/terasology/logic/players/CameraClientSystem.java @@ -118,7 +118,7 @@ private void mountCamera() { // if the camera already has a location, use that as the relative position of the camera if (cameraLocation != null) { - Location.attachChild(targetEntityForCamera, clientComponent.camera, JomlUtil.from(cameraLocation.getLocalPosition()), new Quaternionf()); + Location.attachChild(targetEntityForCamera, clientComponent.camera, cameraLocation.getLocalPosition(), new Quaternionf()); } else { Location.attachChild(targetEntityForCamera, clientComponent.camera, new Vector3f(0, 0, 0), new Quaternionf()); } From 994933bbe7c464e6eed3b5178152a810ea840532 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:23:34 -0800 Subject: [PATCH 180/259] build(PC): make logger local to file --- buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index f08380d5b99..0ca51e58747 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -12,7 +12,7 @@ import org.gradle.api.tasks.SourceSetContainer import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.the -val logger: Logger = Logging.getLogger("org.tersology.gradology") +private val logger: Logger = Logging.getLogger("org.tersology.gradology.exec") /** * The subdirectory for this development environment. From 29cae4d8f6f12bfb042573cb12ee19d37404709a Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 1 Feb 2021 23:14:37 -0800 Subject: [PATCH 181/259] build(PC): gitignore module cache --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d925a13058..b6d624113e9 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ Thumbs.db /configs/ /screenshots/ /logs/ +/moduleCache/ /terasology-server/ /terasology-2ndclient/ /terasology-3rdclient/ From 3b0d371fa7ddf8e919b2b3fc2e9d18b935250eee Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Mon, 1 Feb 2021 23:19:40 -0800 Subject: [PATCH 182/259] build(PC): compile-only dependency on module cache Including the module cache in compileOnly lets IntelliJ know about the dependency without adding to the runtime classpath. Also: Use lenient dependency resolution for module cache. Better chance of being able to start PC with temporary module failures. --- buildSrc/src/main/kotlin/facade.gradle.kts | 25 +++--- .../org/terasology/gradology/module_deps.kt | 86 +++++++++++++++++++ .../main/kotlin/terasology-module.gradle.kts | 4 +- 3 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 buildSrc/src/main/kotlin/org/terasology/gradology/module_deps.kt diff --git a/buildSrc/src/main/kotlin/facade.gradle.kts b/buildSrc/src/main/kotlin/facade.gradle.kts index 9896dd4ba1d..2e0e1ca8867 100644 --- a/buildSrc/src/main/kotlin/facade.gradle.kts +++ b/buildSrc/src/main/kotlin/facade.gradle.kts @@ -1,6 +1,8 @@ // Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +import org.terasology.gradology.moduleDependencyArtifacts + plugins { application } @@ -11,18 +13,20 @@ configurations { register("natives") { description = "native libraries (.dll and .so)" } - register("modules") { + val modulesConfig = register("modules") { description = "locally built modules and their dependencies" resolutionStrategy { preferProjectModules() } - - @Suppress("UnstableApiUsage") - shouldResolveConsistentlyWith(configurations["runtimeClasspath"]) + } + named("compileOnly") { + // Include modules in compileOnly so IntelliJ thinks to compile them. + extendsFrom(modulesConfig.get()) } } + dependencies { "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) @@ -33,16 +37,9 @@ dependencies { } tasks.register("provideModuleDependencies") { - dependsOn(configurations["modules"]) - destinationDir = rootProject.file("moduleCache") - from(configurations["modules"].resolvedConfiguration.resolvedArtifacts.mapNotNull { - if ( - (it.moduleVersion.id.group == "org.terasology.modules") and - // FIXME: There must be a better way to filter out things from local projects than - // doing string comparisons on the display name. - (!it.id.componentIdentifier.toString().startsWith("project ")) - ) it.file else null - }) + val modulesConfig = configurations.named("modules") + val artifactsProvider = moduleDependencyArtifacts(modulesConfig) + from(artifactsProvider.map { artifacts -> artifacts.map(ResolvedArtifactResult::getFile) }) } diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/module_deps.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/module_deps.kt new file mode 100644 index 00000000000..639e15aa27b --- /dev/null +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/module_deps.kt @@ -0,0 +1,86 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.gradology + +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ModuleIdentifier +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentIdentifier +import org.gradle.api.artifacts.result.ResolvedArtifactResult +import org.gradle.api.artifacts.result.ResolvedDependencyResult +import org.gradle.api.artifacts.result.UnresolvedDependencyResult +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.provider.Provider + +const val TERASOLOGY_MODULES_GROUP = "org.terasology.modules" + +val ModuleIdentifier.isTerasologyModule: Boolean + get() = group == TERASOLOGY_MODULES_GROUP + +private val logger: Logger = Logging.getLogger("org.tersology.gradology.module_deps") + + +/** + * Retrieve module dependencies. + * + * Finds dependencies of this configuration which are Terasology modules + * and are not provided by local projects. + */ +fun moduleDependencyArtifacts(modulesConfig: Provider): Provider> = + modulesConfig.map { + configuration -> moduleDependencyArtifacts(configuration) + } + + +/** + * Retrieve module dependencies. + * + * Finds dependencies of this configuration which are Terasology modules + * and are not provided by local projects. + */ +fun moduleDependencyArtifacts(modulesConfig: Configuration): Iterable { + // configurations.resolvedConfiguration is more straightforward if you just want all the artifacts, + // but using `.incoming` lets us turn on lenient mode as well as do more accurate filtering of local modules + val resolvable = modulesConfig.incoming + val artifactView = resolvable.artifactView { + lenient(true) + } + + val allDependencies = resolvable.resolutionResult.allDependencies + val resolvedDependencies = allDependencies.mapNotNull { + if (it is ResolvedDependencyResult) { + return@mapNotNull it + } + if (it is UnresolvedDependencyResult) { + logger.warn("Dependency {} of {} not resolved:", it.attempted, it.from, it.failure) + } else { + logger.warn( + "Dependency {} of {} not resolved: Unexpected result class {}\n{}", + it.requested, + it.from, + it::class, + it + ) + } + null + } + val moduleIdentifiers: Set = resolvedDependencies.mapNotNull { dependency -> + val moduleId = when (val selectedId = dependency.selected.id) { + is ProjectComponentIdentifier -> null // local source + is ModuleComponentIdentifier -> selectedId.moduleIdentifier + else -> error("What type is ${selectedId::class}?") + } + moduleId?.takeIf { it.isTerasologyModule } + }.toSet() + + val moduleArtifacts = artifactView.artifacts.filter { artifact -> + val moduleId = (artifact.id.componentIdentifier as? ModuleComponentIdentifier)?.moduleIdentifier + moduleId != null && moduleIdentifiers.contains(moduleId) + } + logger.debug("Resolved artifacts for {} modules.", { moduleIdentifiers.size }) + return moduleArtifacts +} + + diff --git a/buildSrc/src/main/kotlin/terasology-module.gradle.kts b/buildSrc/src/main/kotlin/terasology-module.gradle.kts index 0df4c4b197f..34dab0badaf 100644 --- a/buildSrc/src/main/kotlin/terasology-module.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-module.gradle.kts @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 // Simple build file for modules - the one under the Core module is the template, will be copied as needed to modules @@ -13,7 +13,7 @@ import org.reflections.util.FilterBuilder import org.terasology.module.ModuleMetadataJsonAdapter plugins { - id("java") + `java-library` id("idea") id("eclipse") } From 8a1532d8acdeec39f617ac5de51ab2e72088a773 Mon Sep 17 00:00:00 2001 From: 4Denthusiast <25589515+4Denthusiast@users.noreply.github.com> Date: Tue, 2 Feb 2021 17:56:39 +0000 Subject: [PATCH 183/259] feat: Enable extreme render distances using LOD chunks (#4452) * Add unscaled LOD chunks * Make further-away LOD chunks larger * Add scalable world generation for LOD chunks * Improve LOD chunk loading logic * Make the loaded region more symmetrical. --- .../Zones/LayeredZoneRegionFunctionTest.java | 2 +- .../terasology/config/RenderingConfig.java | 12 + .../renderer/HeadlessWorldRenderer.java | 2 +- .../terasology/rendering/AABBRenderer.java | 7 +- .../rendering/cameras/PerspectiveCamera.java | 23 +- .../rendering/cameras/SubmersibleCamera.java | 2 +- .../videoSettings/VideoSettingsScreen.java | 9 + .../BlockMeshGeneratorSingleShape.java | 6 +- .../primitives/ChunkTessellator.java | 26 +- .../world/ChunkMeshUpdateManager.java | 2 +- .../rendering/world/RenderQueuesHelper.java | 11 + .../rendering/world/RenderableWorld.java | 2 +- .../rendering/world/RenderableWorldImpl.java | 64 +++- .../rendering/world/WorldRenderer.java | 3 +- .../rendering/world/WorldRendererImpl.java | 7 +- .../ClientViewDistanceSystem.java | 18 +- .../utilities/procedural/SubSampledNoise.java | 20 +- .../world/RelevanceRegionComponent.java | 1 - .../terasology/world/chunks/CoreChunk.java | 24 +- .../org/terasology/world/chunks/LodChunk.java | 319 ++++++++++++++++++ .../world/chunks/LodChunkProvider.java | 265 +++++++++++++++ .../world/chunks/internal/ChunkImpl.java | 4 +- .../world/chunks/internal/PreLodChunk.java | 38 +++ .../LocalChunkProvider.java | 5 +- .../pipeline/ChunkProcessingPipeline.java | 6 + .../RemoteChunkProvider.java | 3 +- .../generation/BaseFacetedWorldGenerator.java | 8 +- .../world/generation/RegionImpl.java | 10 +- .../generation/ScalableFacetProvider.java | 12 + .../generation/ScalableWorldRasterizer.java | 15 + .../terasology/world/generation/World.java | 8 +- .../world/generation/WorldBuilder.java | 92 +++-- .../world/generation/WorldImpl.java | 23 +- .../generator/ScalableWorldGenerator.java | 17 + .../world/propagation/PropagationRules.java | 3 +- .../propagation/StandardBatchPropagator.java | 12 +- .../SunlightRegenBatchPropagator.java | 2 +- .../light/InternalLightProcessor.java | 26 +- .../light/LightPropagationRules.java | 4 +- .../light/SunlightPropagationRules.java | 4 +- .../light/SunlightRegenPropagationRules.java | 4 +- .../src/main/resources/assets/i18n/menu.lang | 1 + .../main/resources/assets/i18n/menu_en.lang | 1 + .../assets/ui/menu/videoMenuScreen.ui | 8 + 44 files changed, 1011 insertions(+), 120 deletions(-) create mode 100644 engine/src/main/java/org/terasology/world/chunks/LodChunk.java create mode 100644 engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java create mode 100644 engine/src/main/java/org/terasology/world/chunks/internal/PreLodChunk.java create mode 100644 engine/src/main/java/org/terasology/world/generation/ScalableFacetProvider.java create mode 100644 engine/src/main/java/org/terasology/world/generation/ScalableWorldRasterizer.java create mode 100644 engine/src/main/java/org/terasology/world/generator/ScalableWorldGenerator.java diff --git a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java index e0feb3f0717..22a77e8cd05 100644 --- a/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java +++ b/engine-tests/src/test/java/org/terasology/world/Zones/LayeredZoneRegionFunctionTest.java @@ -78,7 +78,7 @@ public void setup() { borders.put(ElevationFacet.class, new Border3D(0, 0, 0)); region = new RegionImpl(new BlockRegion(0, 0, 0).expand(4, 4, 4), - facetProviderChains, borders); + facetProviderChains, borders, 1); } @Test diff --git a/engine/src/main/java/org/terasology/config/RenderingConfig.java b/engine/src/main/java/org/terasology/config/RenderingConfig.java index 808088aeea0..c50e6505974 100644 --- a/engine/src/main/java/org/terasology/config/RenderingConfig.java +++ b/engine/src/main/java/org/terasology/config/RenderingConfig.java @@ -38,6 +38,7 @@ public class RenderingConfig extends AbstractSubscribable { public static final String RESOLUTION = "Resolution"; public static final String ANIMATED_MENU = "AnimatedMenu"; public static final String VIEW_DISTANCE = "viewDistance"; + public static final String CHUNK_LODS = "chunkLods"; public static final String FLICKERING_LIGHT = "FlickeringLight"; public static final String ANIMATE_GRASS = "AnimateGrass"; public static final String ANIMATE_WATER = "AnimateWater"; @@ -87,6 +88,7 @@ public class RenderingConfig extends AbstractSubscribable { private Resolution resolution; private boolean animatedMenu; private ViewDistance viewDistance; + private float chunkLods; private boolean flickeringLight; private boolean animateGrass; private boolean animateWater; @@ -271,6 +273,16 @@ public void setViewDistance(ViewDistance viewDistance) { propertyChangeSupport.firePropertyChange(VIEW_DISTANCE, oldDistance, viewDistance); } + public float getChunkLods() { + return chunkLods; + } + + public void setChunkLods(float chunkLods) { + float oldLods = this.chunkLods; + this.chunkLods = chunkLods; + propertyChangeSupport.firePropertyChange(CHUNK_LODS, oldLods, chunkLods); + } + public boolean isFlickeringLight() { return flickeringLight; } diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java index c7f17dfa46f..97b6d232a2b 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java @@ -142,7 +142,7 @@ public boolean pregenerateChunks() { } @Override - public void setViewDistance(ViewDistance viewDistance) { + public void setViewDistance(ViewDistance viewDistance, int chunkLods) { // TODO Auto-generated method stub } diff --git a/engine/src/main/java/org/terasology/rendering/AABBRenderer.java b/engine/src/main/java/org/terasology/rendering/AABBRenderer.java index 94207edf319..a2e90a949fd 100644 --- a/engine/src/main/java/org/terasology/rendering/AABBRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/AABBRenderer.java @@ -93,7 +93,7 @@ public void render() { glPushMatrix(); Vector3f cameraPosition = CoreRegistry.get(LocalPlayer.class).getViewPosition(new Vector3f()); Vector3f center = aabb.center(new Vector3f()); - glTranslated(center.x - cameraPosition.x, -cameraPosition.y, center.z - cameraPosition.z); + glTranslated(center.x - cameraPosition.x, center.y - cameraPosition.y, center.z - cameraPosition.z); renderLocally(); @@ -126,13 +126,8 @@ public void renderLocally() { if (displayListWire == -1) { generateDisplayListWire(); } - Vector3f center = aabb.center(new Vector3f()); - glPushMatrix(); - glTranslated(0f, center.y, 0f); glCallList(displayListWire); - - glPopMatrix(); } public void renderSolidLocally() { diff --git a/engine/src/main/java/org/terasology/rendering/cameras/PerspectiveCamera.java b/engine/src/main/java/org/terasology/rendering/cameras/PerspectiveCamera.java index eff0123920b..ea6ca6a3d1e 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/PerspectiveCamera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/PerspectiveCamera.java @@ -11,6 +11,7 @@ import org.terasology.math.TeraMath; import org.terasology.rendering.nui.layers.mainMenu.videoSettings.CameraSetting; import org.terasology.world.WorldProvider; +import org.terasology.world.chunks.Chunks; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -48,6 +49,9 @@ public PerspectiveCamera(WorldProvider worldProvider, RenderingConfig renderingC this.cameraSettings = renderingConfig.getCameraSettings(); displayDevice.subscribe(DISPLAY_RESOLUTION_CHANGE, this); + renderingConfig.subscribe(RenderingConfig.VIEW_DISTANCE, this); + renderingConfig.subscribe(RenderingConfig.CHUNK_LODS, this); + updateFarClippingDistance(); } @Override @@ -181,10 +185,23 @@ public void setBobbingVerticalOffsetFactor(float f) { bobbingVerticalOffsetFactor = f; } + private void updateFarClippingDistance() { + float distance = renderingConfig.getViewDistance().getChunkDistance().x() * Chunks.SIZE_X * (1 << (int) renderingConfig.getChunkLods()); + zFar = Math.max(distance, 500) * 2; + // distance is an estimate of how far away the farthest chunks are, and the minimum bound is to ensure that the sky is visible. + } + public void propertyChange(PropertyChangeEvent propertyChangeEvent) { - if (propertyChangeEvent.getPropertyName().equals(DISPLAY_RESOLUTION_CHANGE)) { - cachedFov = -1; // Invalidate the cache, so that matrices get regenerated. - updateMatrices(); + switch (propertyChangeEvent.getPropertyName()) { + case DISPLAY_RESOLUTION_CHANGE: + cachedFov = -1; // Invalidate the cache, so that matrices get regenerated. + updateMatrices(); + return; + case RenderingConfig.VIEW_DISTANCE: + case RenderingConfig.CHUNK_LODS: + updateFarClippingDistance(); + return; + default: } } } diff --git a/engine/src/main/java/org/terasology/rendering/cameras/SubmersibleCamera.java b/engine/src/main/java/org/terasology/rendering/cameras/SubmersibleCamera.java index f273a0549f4..c5c0bffbe89 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/SubmersibleCamera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/SubmersibleCamera.java @@ -24,7 +24,7 @@ public abstract class SubmersibleCamera extends Camera { /* Used for Underwater Checks */ private WorldProvider worldProvider; - private RenderingConfig renderingConfig; + RenderingConfig renderingConfig; public SubmersibleCamera(WorldProvider worldProvider, RenderingConfig renderingConfig) { this.worldProvider = worldProvider; diff --git a/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/videoSettings/VideoSettingsScreen.java b/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/videoSettings/VideoSettingsScreen.java index 4ea0cf3d23f..852cc6d5c49 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/videoSettings/VideoSettingsScreen.java +++ b/engine/src/main/java/org/terasology/rendering/nui/layers/mainMenu/videoSettings/VideoSettingsScreen.java @@ -154,6 +154,15 @@ public String getString(Integer value) { fovSlider.bindValue(BindHelper.bindBeanProperty("fieldOfView", config.getRendering(), Float.TYPE)); } + final UISlider chunkLodSlider = find("chunkLods", UISlider.class); + if (chunkLodSlider != null) { + chunkLodSlider.setIncrement(1); + chunkLodSlider.setPrecision(0); + chunkLodSlider.setMinimum(0); + chunkLodSlider.setRange(10); + chunkLodSlider.bindValue(BindHelper.bindBeanProperty("chunkLods", config.getRendering(), Float.TYPE)); + } + final UISlider frameLimitSlider = find("frameLimit", UISlider.class); if (frameLimitSlider != null) { frameLimitSlider.setIncrement(5.0f); diff --git a/engine/src/main/java/org/terasology/rendering/primitives/BlockMeshGeneratorSingleShape.java b/engine/src/main/java/org/terasology/rendering/primitives/BlockMeshGeneratorSingleShape.java index 2ddf5f49d13..909eddd6a51 100644 --- a/engine/src/main/java/org/terasology/rendering/primitives/BlockMeshGeneratorSingleShape.java +++ b/engine/src/main/java/org/terasology/rendering/primitives/BlockMeshGeneratorSingleShape.java @@ -145,10 +145,14 @@ private boolean isSideVisibleForBlockTypes(Block blockToCheck, Block currentBloc //TODO: This only fixes the "water under block" issue of the top side not being rendered. (see bug #3889) //Note: originally tried .isLiquid() instead of isWater for both checks, but IntelliJ was warning that // !blockToCheck.isWater() is always true, may need further investigation - if (currentBlock.isWater() && (side == Side.TOP) && !blockToCheck.isWater()){ + if (currentBlock.isWater() && (side == Side.TOP) && !blockToCheck.isWater()) { return true; } + if (blockToCheck.getURI().toString().equals("engine:unloaded")) { + return false; + } + return currentBlock.isWaving() != blockToCheck.isWaving() || blockToCheck.getMeshGenerator() == null || !blockToCheck.isFullSide(side.reverse()) || (!currentBlock.isTranslucent() && blockToCheck.isTranslucent()); diff --git a/engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java b/engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java index 90ed5b926c1..bae262854e7 100644 --- a/engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java +++ b/engine/src/main/java/org/terasology/rendering/primitives/ChunkTessellator.java @@ -17,6 +17,7 @@ import com.google.common.base.Stopwatch; import gnu.trove.iterator.TIntIterator; +import gnu.trove.list.TFloatList; import org.lwjgl.BufferUtils; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.math.Direction; @@ -27,6 +28,7 @@ import org.terasology.world.ChunkView; import org.terasology.world.block.Block; import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import java.util.concurrent.TimeUnit; @@ -44,15 +46,20 @@ public ChunkTessellator(GLBufferPool bufferPool) { this.bufferPool = bufferPool; } - public ChunkMesh generateMesh(ChunkView chunkView, int meshHeight, int verticalOffset) { + public ChunkMesh generateMesh(ChunkView chunkView) { + return generateMesh(chunkView, 1, 0); + } + + public ChunkMesh generateMesh(ChunkView chunkView, float scale, int border) { PerformanceMonitor.startActivity("GenerateMesh"); ChunkMesh mesh = new ChunkMesh(bufferPool); final Stopwatch watch = Stopwatch.createStarted(); - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { - for (int y = verticalOffset; y < verticalOffset + meshHeight; y++) { + // The mesh extends into the borders in the horizontal directions, but not vertically upwards, in order to cover gaps between LOD chunks of different scales, but also avoid multiple overlapping ocean surfaces. + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { + for (int y = 0; y < Chunks.SIZE_Y - border * 2; y++) { Block block = chunkView.getBlock(x, y, z); if (block != null && block.getMeshGenerator() != null) { block.getMeshGenerator().generateChunkMesh(chunkView, mesh, x, y, z); @@ -65,7 +72,7 @@ public ChunkMesh generateMesh(ChunkView chunkView, int meshHeight, int verticalO mesh.setTimeToGenerateBlockVertices((int) watch.elapsed(TimeUnit.MILLISECONDS)); watch.reset().start(); - generateOptimizedBuffers(chunkView, mesh); + generateOptimizedBuffers(chunkView, mesh, scale, border); watch.stop(); mesh.setTimeToGenerateOptimizedBuffers((int) watch.elapsed(TimeUnit.MILLISECONDS)); statVertexArrayUpdateCount++; @@ -74,7 +81,7 @@ public ChunkMesh generateMesh(ChunkView chunkView, int meshHeight, int verticalO return mesh; } - private void generateOptimizedBuffers(ChunkView chunkView, ChunkMesh mesh) { + private void generateOptimizedBuffers(ChunkView chunkView, ChunkMesh mesh, float scale, float border) { PerformanceMonitor.startActivity("OptimizeBuffers"); for (ChunkMesh.RenderType type : ChunkMesh.RenderType.values()) { @@ -97,9 +104,10 @@ private void generateOptimizedBuffers(ChunkView chunkView, ChunkMesh mesh) { elements.vertices.get(i * 3 + 2)); /* POSITION */ - elements.finalVertices.put(Float.floatToIntBits(vertexPos.x)); - elements.finalVertices.put(Float.floatToIntBits(vertexPos.y)); - elements.finalVertices.put(Float.floatToIntBits(vertexPos.z)); + float totalScale = scale * Chunks.SIZE_X / (Chunks.SIZE_X - 2 * border); + elements.finalVertices.put(Float.floatToIntBits((vertexPos.x - border) * totalScale)); + elements.finalVertices.put(Float.floatToIntBits((vertexPos.y - 2 * border) * totalScale)); + elements.finalVertices.put(Float.floatToIntBits((vertexPos.z - border) * totalScale)); /* UV0 - TEX DATA 0.xy */ elements.finalVertices.put(Float.floatToIntBits(elements.tex.get(i * 2))); diff --git a/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java b/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java index b3260c34c6f..a66074ea5eb 100644 --- a/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java +++ b/engine/src/main/java/org/terasology/rendering/world/ChunkMeshUpdateManager.java @@ -170,7 +170,7 @@ public void run() { */ c.setDirty(false); if (chunkView.isValidView()) { - newMesh = tessellator.generateMesh(chunkView, ChunkConstants.SIZE_Y, 0); + newMesh = tessellator.generateMesh(chunkView); c.setPendingMesh(newMesh); ChunkMonitor.fireChunkTessellated(c.getPosition(new org.joml.Vector3i()), newMesh); diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderQueuesHelper.java b/engine/src/main/java/org/terasology/rendering/world/RenderQueuesHelper.java index b208932cef4..15a07ac14ae 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderQueuesHelper.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderQueuesHelper.java @@ -38,4 +38,15 @@ public class RenderQueuesHelper { this.chunksAlphaReject = chunksAlphaReject; this.chunksAlphaBlend = chunksAlphaBlend; } + + /** + * Remove any remaining data from all queues, to avoid a memory leak in the case that the nodes using that data aren't present. + */ + public void clear() { + chunksOpaque.clear(); + chunksOpaqueShadow.clear(); + chunksOpaqueReflection.clear(); + chunksAlphaReject.clear(); + chunksAlphaBlend.clear(); + } } diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java index c26b6ab61e2..2bc18809865 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorld.java @@ -36,7 +36,7 @@ public interface RenderableWorld { boolean updateChunksInProximity(BlockRegion renderableRegion); - boolean updateChunksInProximity(ViewDistance viewDistance); + boolean updateChunksInProximity(ViewDistance viewDistance, int chunkLods); void generateVBOs(); diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index 8da80748ba6..1804017a4e2 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory; import org.terasology.config.Config; import org.terasology.config.RenderingConfig; +import org.terasology.context.Context; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.joml.geom.AABBi; import org.terasology.math.JomlUtil; @@ -36,12 +37,19 @@ import org.terasology.rendering.world.viewDistance.ViewDistance; import org.terasology.world.ChunkView; import org.terasology.world.WorldProvider; +import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; +import org.terasology.world.chunks.LodChunk; +import org.terasology.world.chunks.LodChunkProvider; import org.terasology.world.chunks.RenderableChunk; +import org.terasology.world.generator.ScalableWorldGenerator; +import org.terasology.world.generator.WorldGenerator; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -64,6 +72,7 @@ class RenderableWorldImpl implements RenderableWorld { private final WorldProvider worldProvider; private ChunkProvider chunkProvider; + private LodChunkProvider lodChunkProvider; private ChunkTessellator chunkTessellator; private final ChunkMeshUpdateManager chunkMeshUpdateManager; @@ -83,17 +92,20 @@ class RenderableWorldImpl implements RenderableWorld { private int statIgnoredPhases; - RenderableWorldImpl(WorldProvider worldProvider, - ChunkProvider chunkProvider, - GLBufferPool bufferPool, - Camera playerCamera) { + RenderableWorldImpl(Context context, GLBufferPool bufferPool, Camera playerCamera) { - this.worldProvider = worldProvider; - this.chunkProvider = chunkProvider; + worldProvider = context.get(WorldProvider.class); + chunkProvider = context.get(ChunkProvider.class); chunkTessellator = new ChunkTessellator(bufferPool); chunkMeshUpdateManager = new ChunkMeshUpdateManager(chunkTessellator, worldProvider); this.playerCamera = playerCamera; + WorldGenerator worldGenerator = context.get(WorldGenerator.class); + if (worldGenerator instanceof ScalableWorldGenerator) { + lodChunkProvider = new LodChunkProvider(context, (ScalableWorldGenerator) worldGenerator, chunkTessellator, renderingConfig.getViewDistance(), (int) renderingConfig.getChunkLods(), calcCameraCoordinatesInChunkUnits()); + } else { + lodChunkProvider = null; + } renderQueues = new RenderQueuesHelper(new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), @@ -109,6 +121,9 @@ public void onChunkLoaded(Vector3ic chunkCoordinates) { if (chunk != null) { chunksInProximityOfCamera.add(chunk); Collections.sort(chunksInProximityOfCamera, new ChunkFrontToBackComparator()); + if (lodChunkProvider != null) { + lodChunkProvider.onRealChunkLoaded(chunkCoordinates); + } } else { logger.warn("Warning: onChunkLoaded called for a null chunk!"); } @@ -135,6 +150,9 @@ public void onChunkUnloaded(Vector3ic chunkCoordinates) { } } } + if (lodChunkProvider != null) { + lodChunkProvider.onRealChunkUnloaded(chunkCoordinates); + } } /** @@ -160,7 +178,7 @@ public boolean pregenerateChunks() { } chunk.setDirty(false); - newMesh = chunkTessellator.generateMesh(localView, ChunkConstants.SIZE_Y, 0); + newMesh = chunkTessellator.generateMesh(localView); newMesh.generateVBOs(); if (chunk.hasMesh()) { @@ -190,6 +208,11 @@ public void update() { updateChunksInProximity(calculateRenderableRegion(renderingConfig.getViewDistance())); PerformanceMonitor.endActivity(); + if (lodChunkProvider != null) { + PerformanceMonitor.startActivity("Update LOD Chunks"); + lodChunkProvider.update(calcCameraCoordinatesInChunkUnits()); + PerformanceMonitor.endActivity(); + } } /** @@ -237,10 +260,13 @@ public boolean updateChunksInProximity(BlockRegion newRenderableRegion) { } @Override - public boolean updateChunksInProximity(ViewDistance newViewDistance) { - if (newViewDistance != currentViewDistance) { + public boolean updateChunksInProximity(ViewDistance newViewDistance, int chunkLods) { + if (newViewDistance != currentViewDistance || (lodChunkProvider != null && chunkLods != lodChunkProvider.getChunkLods())) { logger.info("New Viewing Distance: {}", newViewDistance); currentViewDistance = newViewDistance; + if (lodChunkProvider != null) { + lodChunkProvider.updateRenderableRegion(newViewDistance, chunkLods, calcCameraCoordinatesInChunkUnits()); + } return updateChunksInProximity(calculateRenderableRegion(newViewDistance)); } else { return false; @@ -261,9 +287,7 @@ private BlockRegion calculateRenderableRegion(ViewDistance newViewDistance) { */ private Vector3i calcCameraCoordinatesInChunkUnits() { org.joml.Vector3f cameraCoordinates = playerCamera.getPosition(); - return new Vector3i((int) (cameraCoordinates.x() / ChunkConstants.SIZE_X), - (int) (cameraCoordinates.y() / ChunkConstants.SIZE_Y), - (int) (cameraCoordinates.z() / ChunkConstants.SIZE_Z)); + return Chunks.toChunkPos(cameraCoordinates, new Vector3i()); } @Override @@ -304,10 +328,21 @@ public int queueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame) { int processedChunks = 0; int chunkCounter = 0; + + renderQueues.clear(); + ChunkMesh mesh; boolean isDynamicShadows = renderingConfig.isDynamicShadows(); - for (RenderableChunk chunk : chunksInProximityOfCamera) { + List allChunks; + if (lodChunkProvider != null) { + allChunks = new ArrayList<>(chunksInProximityOfCamera); + allChunks.addAll(lodChunkProvider.getChunks()); + } else { + allChunks = chunksInProximityOfCamera; + } + + for (RenderableChunk chunk : allChunks) { if (isChunkValidForRender(chunk)) { mesh = chunk.getMesh(); @@ -376,6 +411,9 @@ private int triangleCount(ChunkMesh mesh, ChunkMesh.RenderPhase renderPhase) { @Override public void dispose() { chunkMeshUpdateManager.shutdown(); + if (lodChunkProvider != null) { + lodChunkProvider.shutdown(); + } } private boolean isChunkValidForRender(RenderableChunk chunk) { diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java b/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java index bdeab0deacf..c5f0ccd263f 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java @@ -167,8 +167,9 @@ enum RenderingStage { * Sets how far from the camera chunks are kept in memory and displayed. * * @param viewDistance a viewDistance value. + * @param chunkLods the number of LOD levels to display beyond the loaded chunks. */ - void setViewDistance(ViewDistance viewDistance); + void setViewDistance(ViewDistance viewDistance, int chunkLods); /** * Returns the intensity of the light at a given location due to the combination of main light (sun or moon) diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java index 55f66d06917..9d8fcf5e7b2 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java @@ -56,7 +56,6 @@ import org.terasology.rendering.world.viewDistance.ViewDistance; import org.terasology.utilities.Assets; import org.terasology.world.WorldProvider; -import org.terasology.world.chunks.ChunkProvider; import java.util.List; @@ -168,7 +167,7 @@ public WorldRendererImpl(Context context, GLBufferPool bufferPool) { LocalPlayerSystem localPlayerSystem = context.get(LocalPlayerSystem.class); localPlayerSystem.setPlayerCamera(playerCamera); - renderableWorld = new RenderableWorldImpl(worldProvider, context.get(ChunkProvider.class), bufferPool, playerCamera); + renderableWorld = new RenderableWorldImpl(context, bufferPool, playerCamera); renderQueues = renderableWorld.getRenderQueues(); initRenderingSupport(); @@ -393,8 +392,8 @@ public void dispose() { } @Override - public void setViewDistance(ViewDistance viewDistance) { - renderableWorld.updateChunksInProximity(viewDistance); + public void setViewDistance(ViewDistance viewDistance, int chunkLods) { + renderableWorld.updateChunksInProximity(viewDistance, chunkLods); } @Override diff --git a/engine/src/main/java/org/terasology/rendering/world/viewDistance/ClientViewDistanceSystem.java b/engine/src/main/java/org/terasology/rendering/world/viewDistance/ClientViewDistanceSystem.java index c2e318f18a9..069979646e0 100644 --- a/engine/src/main/java/org/terasology/rendering/world/viewDistance/ClientViewDistanceSystem.java +++ b/engine/src/main/java/org/terasology/rendering/world/viewDistance/ClientViewDistanceSystem.java @@ -56,27 +56,35 @@ public class ClientViewDistanceSystem extends BaseComponentSystem { @In private LocalPlayer localPlayer; - private PropertyChangeListener propertyChangeListener; + private PropertyChangeListener viewDistanceListener; + private PropertyChangeListener chunkLodsListener; private TranslationSystem translationSystem; @Override public void initialise() { - propertyChangeListener = evt -> { + viewDistanceListener = evt -> { if (evt.getPropertyName().equals(RenderingConfig.VIEW_DISTANCE)) { onChangeViewDistanceChange(); } }; - config.getRendering().subscribe(propertyChangeListener); + config.getRendering().subscribe(viewDistanceListener); + chunkLodsListener = evt -> { + if (evt.getPropertyName().equals(RenderingConfig.CHUNK_LODS)) { + onChangeViewDistanceChange(); + } + }; + config.getRendering().subscribe(chunkLodsListener); translationSystem = new TranslationSystemImpl(context); } public void onChangeViewDistanceChange() { ViewDistance viewDistance = config.getRendering().getViewDistance(); + int chunkLods = (int) config.getRendering().getChunkLods(); if (worldRenderer != null) { - worldRenderer.setViewDistance(viewDistance); + worldRenderer.setViewDistance(viewDistance, chunkLods); } EntityRef clientEntity = localPlayer.getClientEntity(); @@ -85,7 +93,7 @@ public void onChangeViewDistanceChange() { @Override public void shutdown() { - config.getRendering().unsubscribe(propertyChangeListener); + config.getRendering().unsubscribe(viewDistanceListener); } /** diff --git a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java index ff5c0ca50e3..f448e0c2025 100644 --- a/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java +++ b/engine/src/main/java/org/terasology/utilities/procedural/SubSampledNoise.java @@ -80,8 +80,12 @@ public float[] noise(Rect2i region) { } public float[] noise(BlockAreac area) { + return noise(area, 1); + } + + public float[] noise(BlockAreac area, float scale) { BlockArea fullRegion = determineRequiredRegion(area); - float[] keyData = getKeyValues(fullRegion); + float[] keyData = getKeyValues(fullRegion, scale); float[] fullData = mapExpand(keyData, fullRegion); return getSubset(fullData, fullRegion, area); } @@ -120,7 +124,7 @@ private float[] mapExpand(float[] keyData, BlockAreac fullRegion) { return fullData; } - private float[] getKeyValues(BlockAreac fullRegion) { + private float[] getKeyValues(BlockAreac fullRegion, float scale) { int xDim = fullRegion.getSizeX() / sampleRate + 1; int yDim = fullRegion.getSizeY() / sampleRate + 1; float[] fullData = new float[xDim * yDim]; @@ -128,7 +132,7 @@ private float[] getKeyValues(BlockAreac fullRegion) { for (int x = 0; x < xDim; x++) { int actualX = x * sampleRate + fullRegion.minX(); int actualY = y * sampleRate + fullRegion.minY(); - fullData[x + y * xDim] = source.noise(zoom.x * actualX, zoom.y * actualY); + fullData[x + y * xDim] = source.noise(zoom.x * scale * actualX, zoom.y * scale * actualY); } } @@ -168,8 +172,12 @@ public float noise(float x, float y, float z) { } public float[] noise(BlockRegion region) { + return noise(region, 1); + } + + public float[] noise(BlockRegion region, float scale) { BlockRegion fullRegion = determineRequiredRegion(region); - float[] keyData = getKeyValues(fullRegion); + float[] keyData = getKeyValues(fullRegion, scale); float[] fullData = mapExpand(keyData, fullRegion); return getSubset(fullData, fullRegion, region); } @@ -222,7 +230,7 @@ private float[] mapExpand(float[] keyData, BlockRegion fullRegion) { return fullData; } - private float[] getKeyValues(BlockRegion fullRegion) { + private float[] getKeyValues(BlockRegion fullRegion, float scale) { int xDim = fullRegion.getSizeX() / sampleRate + 1; int yDim = fullRegion.getSizeY() / sampleRate + 1; int zDim = fullRegion.getSizeZ() / sampleRate + 1; @@ -233,7 +241,7 @@ private float[] getKeyValues(BlockRegion fullRegion) { int actualX = x * sampleRate + fullRegion.minX(); int actualY = y * sampleRate + fullRegion.minY(); int actualZ = z * sampleRate + fullRegion.minZ(); - fullData[x + xDim * (y + yDim * z)] = source.noise(zoom.x * actualX, zoom.y * actualY, zoom.z * actualZ); + fullData[x + xDim * (y + yDim * z)] = source.noise(zoom.x * scale * actualX, zoom.y * scale * actualY, zoom.z * scale * actualZ); } } } diff --git a/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java b/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java index ba10bf1a4df..0819c7adcd2 100644 --- a/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java +++ b/engine/src/main/java/org/terasology/world/RelevanceRegionComponent.java @@ -23,5 +23,4 @@ public class RelevanceRegionComponent implements Component { public Vector3i distance = new Vector3i(1, 1, 1); - } diff --git a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java index 74ad0a763e4..c6f986546eb 100644 --- a/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/CoreChunk.java @@ -25,7 +25,7 @@ public interface CoreChunk { /** - * @return Position of the chunk in world, where units of distance from origin are blocks + * @return Position of the chunk in world, where units of distance from origin are chunks * @deprecated This method is scheduled for removal in an upcoming version. * Use the JOML implementation instead: {@link #getPosition(org.joml.Vector3i)}. */ @@ -33,7 +33,7 @@ public interface CoreChunk { Vector3i getPosition(); /** - * Position of the chunk in world, where units of distance from origin are blocks + * Position of the chunk in world, where units of distance from origin are chunks * * @param dest will hold the result * @return dest @@ -174,9 +174,9 @@ public interface CoreChunk { int getExtraData(int index, Vector3ic pos); /** - * Returns offset of this chunk to the world center (0:0:0), with one unit being one chunk. + * Returns offset of this chunk to the world center (0:0:0), with one unit being one block. * - * @return Offset of this chunk from world center in chunks + * @return Offset of this chunk from world center in blocks * @deprecated This method is scheduled for removal in an upcoming version. * Use the JOML implementation instead: {@link #getChunkWorldOffset(org.joml.Vector3i)}. */ @@ -184,31 +184,31 @@ public interface CoreChunk { Vector3i getChunkWorldOffset(); /** - * Returns offset of this chunk to the world center (0:0:0), with one unit being one chunk. + * Returns offset of this chunk to the world center (0:0:0), with one unit being one block. * - * @return Offset of this chunk from world center in chunks + * @return Offset of this chunk from world center in blocks */ org.joml.Vector3i getChunkWorldOffset(org.joml.Vector3i pos); /** - * Returns X offset of this chunk to the world center (0:0:0), with one unit being one chunk. + * Returns X offset of this chunk to the world center (0:0:0), with one unit being one block. * - * @return X offset of this chunk from world center in chunks + * @return X offset of this chunk from world center in blocks */ int getChunkWorldOffsetX(); /** - * Returns Y offset of this chunk to the world center (0:0:0), with one unit being one chunk. + * Returns Y offset of this chunk to the world center (0:0:0), with one unit being one block. * - * @return Y offset of this chunk from world center in chunks + * @return Y offset of this chunk from world center in blocks */ int getChunkWorldOffsetY(); /** - * Returns Z offset of this chunk to the world center (0:0:0), with one unit being one chunk. + * Returns Z offset of this chunk to the world center (0:0:0), with one unit being one block. * - * @return Z offset of this chunk from world center in chunks + * @return Z offset of this chunk from world center in blocks */ int getChunkWorldOffsetZ(); diff --git a/engine/src/main/java/org/terasology/world/chunks/LodChunk.java b/engine/src/main/java/org/terasology/world/chunks/LodChunk.java new file mode 100644 index 00000000000..ffdb7cc224c --- /dev/null +++ b/engine/src/main/java/org/terasology/world/chunks/LodChunk.java @@ -0,0 +1,319 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.chunks; + +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.terasology.joml.geom.AABBf; +import org.terasology.joml.geom.AABBfc; +import org.terasology.math.JomlUtil; +import org.terasology.math.geom.BaseVector3i; +import org.terasology.rendering.primitives.ChunkMesh; +import org.terasology.world.block.Block; +import org.terasology.world.block.BlockRegion; + +/** + * A static, far away chunk that has only the data needed for rendering. + */ +public class LodChunk implements RenderableChunk { + private static final String UNSUPPORTED_MESSAGE = "LOD chunks can only be used for certain rendering-related operations."; + public final int scale; + private Vector3ic position; + private ChunkMesh mesh; + + public LodChunk(Vector3ic pos, ChunkMesh mesh, int scale) { + position = pos; + this.mesh = mesh; + this.scale = scale; + } + + @Override + public org.terasology.math.geom.Vector3i getPosition() { + return JomlUtil.from(position); + } + + @Override + public Vector3i getPosition(Vector3i dest) { + return dest.set(position); + } + + @Override + public org.terasology.math.geom.Vector3i getChunkWorldOffset() { + return JomlUtil.from(position).mul(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z); + } + + @Override + public Vector3i getChunkWorldOffset(Vector3i dest) { + return position.mul(Chunks.CHUNK_SIZE, dest); + } + + @Override + public AABBfc getAABB() { + Vector3f min = new Vector3f(getChunkWorldOffset(new Vector3i())); + return new AABBf(min, new Vector3f(Chunks.CHUNK_SIZE).mul(1 << scale).add(min)); + } + + @Override + public boolean isAnimated() { + return false; + } + + @Override + public void setAnimated(boolean animated) { + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public boolean hasMesh() { + return true; + } + + @Override + public ChunkMesh getMesh() { + return mesh; + } + + @Override + public void setMesh(ChunkMesh newMesh) { + mesh = newMesh; + } + + @Override + public void disposeMesh() { + if (mesh != null) { + mesh.dispose(); + mesh = null; + } + } + + @Override + public boolean isReady() { + return mesh != null; + } + + @Override + public Block getBlock(BaseVector3i pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Block getBlock(Vector3ic pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Block getBlock(int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Block setBlock(int x, int y, int z, Block block) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Block setBlock(BaseVector3i pos, Block block) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Block setBlock(Vector3ic pos, Block block) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public void setExtraData(int index, int x, int y, int z, int value) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public void setExtraData(int index, BaseVector3i pos, int value) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public void setExtraData(int index, Vector3ic pos, int value) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getExtraData(int index, int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getExtraData(int index, BaseVector3i pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getExtraData(int index, Vector3ic pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkWorldOffsetX() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkWorldOffsetY() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkWorldOffsetZ() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public org.terasology.math.geom.Vector3i chunkToWorldPosition(BaseVector3i blockPos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Vector3i chunkToWorldPosition(Vector3ic blockPos, Vector3i dest) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public org.terasology.math.geom.Vector3i chunkToWorldPosition(int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public Vector3i chunkToWorldPosition(int x, int y, int z, Vector3i dest) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int chunkToWorldPositionX(int x) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int chunkToWorldPositionY(int y) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int chunkToWorldPositionZ(int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkSizeX() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkSizeY() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getChunkSizeZ() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public BlockRegion getRegion() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public int getEstimatedMemoryConsumptionInBytes() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public ChunkBlockIterator getBlockIterator() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getSunlight(BaseVector3i pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getSunlight(int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setSunlight(BaseVector3i pos, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setSunlight(int x, int y, int z, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getSunlightRegen(BaseVector3i pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getSunlightRegen(int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setSunlightRegen(BaseVector3i pos, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setSunlightRegen(int x, int y, int z, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getLight(BaseVector3i pos) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public byte getLight(int x, int y, int z) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setLight(BaseVector3i pos, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean setLight(int x, int y, int z, byte amount) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public void setDirty(boolean dirty) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public void setPendingMesh(ChunkMesh newPendingMesh) { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public boolean hasPendingMesh() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } + + @Override + public ChunkMesh getPendingMesh() { + throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); + } +} diff --git a/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java new file mode 100644 index 00000000000..852a485e2c2 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java @@ -0,0 +1,265 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.chunks; + +import com.google.common.collect.Queues; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.context.Context; +import org.terasology.math.JomlUtil; +import org.terasology.rendering.primitives.ChunkMesh; +import org.terasology.rendering.primitives.ChunkTessellator; +import org.terasology.rendering.world.viewDistance.ViewDistance; +import org.terasology.world.ChunkView; +import org.terasology.world.block.Block; +import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; +import org.terasology.world.chunks.internal.PreLodChunk; +import org.terasology.world.generation.impl.EntityBufferImpl; +import org.terasology.world.generator.ScalableWorldGenerator; +import org.terasology.world.internal.ChunkViewCoreImpl; +import org.terasology.world.propagation.light.InternalLightProcessor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.PriorityBlockingQueue; + +public class LodChunkProvider { + private static final Logger logger = LoggerFactory.getLogger(LodChunkProvider.class); + + private ChunkProvider chunkProvider; + private BlockManager blockManager; + private ExtraBlockDataManager extraDataManager; + private ChunkTessellator tessellator; + private ScalableWorldGenerator generator; + + private Vector3i center; + private ViewDistance viewDistanceSetting; + private int chunkLods; + private BlockRegion possiblyLoadedRegion = new BlockRegion(BlockRegion.INVALID); // The chunks that may be actually loaded. + private BlockRegion probablyLoadedRegion = new BlockRegion(BlockRegion.INVALID); // The chunks that should be visible, and therefore shouldn't have LOD chunks even if the chunk there hasn't loaded yet. + private BlockRegion[] lodRegions = new BlockRegion[0]; + private Map requiredChunks; // The sizes of all of the LOD chunks that are meant to exist. + private Map chunks; + private ClosenessComparator nearby; + + // Communication with the generation threads. + private PriorityBlockingQueue neededChunks; + private BlockingQueue readyChunks = Queues.newLinkedBlockingQueue(); + private List generationThreads = new ArrayList<>(); + + public LodChunkProvider(Context context, ScalableWorldGenerator generator, ChunkTessellator tessellator, ViewDistance viewDistance, int chunkLods, Vector3i center) { + chunkProvider = context.get(ChunkProvider.class); + blockManager = context.get(BlockManager.class); + extraDataManager = context.get(ExtraBlockDataManager.class); + this.generator = generator; + this.tessellator = tessellator; + viewDistanceSetting = viewDistance; + this.chunkLods = chunkLods; + this.center = center; + requiredChunks = new ConcurrentHashMap<>(); + chunks = new HashMap<>(); + nearby = new ClosenessComparator(center); + neededChunks = new PriorityBlockingQueue<>(11, nearby); + for (int i = 0; i < 2; i++) { + Thread thread = new Thread(this::createChunks, "LOD Chunk Generation " + i); + thread.start(); + generationThreads.add(thread); + } + } + + private void createChunks() { + Block unloaded = blockManager.getBlock(BlockManager.UNLOADED_ID); + try { + while (true) { + Vector3ic pos = neededChunks.take(); + Integer scale = requiredChunks.get(pos); // Actually the log scale + if (scale == null) { + // This chunk is being removed in the main thread. + continue; + } + Chunk chunk = new PreLodChunk(scaleDown(pos, scale), blockManager, extraDataManager); + generator.createChunk(chunk, new EntityBufferImpl(), (1 << scale) * (2f / (Chunks.SIZE_X - 2) + 1)); + InternalLightProcessor.generateInternalLighting(chunk, 1 << scale); + //tintChunk(chunk); + ChunkView view = new ChunkViewCoreImpl(new Chunk[]{chunk}, new BlockRegion(chunk.getPosition(new Vector3i())), new Vector3i(), unloaded); + ChunkMesh mesh = tessellator.generateMesh(view, 1 << scale, 1); + readyChunks.add(new LodChunk(pos, mesh, scale)); + } + } catch (InterruptedException ignored) { } + } + + private void processReadyChunks() { + while (!readyChunks.isEmpty()) { + LodChunk chunk = readyChunks.remove(); + Vector3i pos = chunk.getPosition(new Vector3i()); + Integer requiredScale = requiredChunks.get(pos); + if (requiredScale != null && requiredScale == chunk.scale) { // The relevant region may have been updated since this chunk was requested. + chunk.getMesh().generateVBOs(); + chunks.put(pos, chunk); + } + } + } + + public void update(Vector3i newCenter) { + updateRenderableRegion(viewDistanceSetting, chunkLods, newCenter); + processReadyChunks(); + } + + public void updateRenderableRegion(ViewDistance newViewDistance, int newChunkLods, Vector3i newCenter) { + viewDistanceSetting = newViewDistance; + center = new Vector3i(delay(center.x, newCenter.x), delay(center.y, newCenter.y), delay(center.z, newCenter.z)); + chunkLods = newChunkLods; + nearby.pos = center; + Vector3i viewDistance = new Vector3i(newViewDistance.getChunkDistance()).div(2); + Vector3i altViewDistance = viewDistance.add(1 - Math.abs(viewDistance.x % 2), 1 - Math.abs(viewDistance.y % 2), 1 - Math.abs(viewDistance.z % 2), new Vector3i()); + BlockRegion newPossiblyLoadedRegion = new BlockRegion(newCenter).expand(viewDistance); + BlockRegion newProbablyLoadedRegion = new BlockRegion(newPossiblyLoadedRegion).expand(-1, -1, -1); + BlockRegion[] newLodRegions = new BlockRegion[newChunkLods == 0 ? 0 : 1 + newChunkLods]; + boolean lodRegionChange = newLodRegions.length != lodRegions.length; + for (int i = 0; i < newLodRegions.length; i++) { + if (i == 0) { + newLodRegions[i] = new BlockRegion(newPossiblyLoadedRegion); + } else { + // By making viewDistance odd, we ensure that every time a chunk boundary is crossed, at most a single lodRegion changes (except possibly for lodRegions[0], which is more closely tied to the renderable region). + newLodRegions[i] = new BlockRegion(scaleDown(center, i)).expand(altViewDistance); + } + Vector3i min = newLodRegions[i].getMin(new Vector3i()); + Vector3i max = newLodRegions[i].getMax(new Vector3i()); + newLodRegions[i].addToMin(-Math.abs(min.x % 2), -Math.abs(min.y % 2), -Math.abs(min.z % 2)); + newLodRegions[i].addToMax(1 - Math.abs(max.x % 2), 1 - Math.abs(max.y % 2), 1 - Math.abs(max.z % 2)); + if (!lodRegionChange && !newLodRegions[i].equals(lodRegions[i])) { + lodRegionChange = true; + } + } + if (lodRegionChange || !newProbablyLoadedRegion.equals(probablyLoadedRegion) || !newPossiblyLoadedRegion.equals(possiblyLoadedRegion)) { + // Remove previously present chunks. + Set previouslyRequiredChunks = new HashSet<>(requiredChunks.keySet()); + for (Vector3ic pos : previouslyRequiredChunks) { + int scale = requiredChunks.get(pos); + if ( + scale >= newLodRegions.length + || !newLodRegions[scale].contains(scaleDown(pos, scale)) + || scale == 0 && newProbablyLoadedRegion.contains(pos) + || scale > 0 && newLodRegions[scale - 1].contains(scaleDown(pos, scale - 1)) + ) { + removeChunk(pos); + } + } + + // Add new chunks. + for (int scale = 0; scale < newLodRegions.length; scale++) { + for (Vector3ic pos : newLodRegions[scale]) { + if ( + scale == 0 && newProbablyLoadedRegion.contains(pos) + || scale == 0 && newPossiblyLoadedRegion.contains(pos) && chunkProvider.isChunkReady(pos) + || scale > 0 && newLodRegions[scale - 1].contains(pos.mul(2, new Vector3i())) + ) { + continue; + } + Vector3i globalPos = pos.mul(1 << scale, new Vector3i()); + if (!requiredChunks.containsKey(globalPos)) { + addChunk(globalPos, scale); + } + } + } + } + lodRegions = newLodRegions; + probablyLoadedRegion = newProbablyLoadedRegion; + possiblyLoadedRegion = newPossiblyLoadedRegion; + } + + public void onRealChunkUnloaded(Vector3ic pos) { + if (chunkLods > 0 && !probablyLoadedRegion.contains(pos) && lodRegions[0].contains(pos) && !requiredChunks.containsKey(pos)) { + addChunk(pos, 0); + } + } + + private void addChunk(Vector3ic pos, int scale) { + if (requiredChunks.containsKey(pos)) { + logger.warn("Duplicate LOD chunk load."); + } + requiredChunks.put(pos, scale); + neededChunks.add(pos); + } + + public void onRealChunkLoaded(Vector3ic pos) { + if (requiredChunks.get(pos) != null && possiblyLoadedRegion.contains(pos) && chunkProvider.isChunkReady(pos)) { + removeChunk(pos); + } + } + + private void removeChunk(Vector3ic pos) { + neededChunks.remove(pos); + requiredChunks.remove(pos); + LodChunk chunk = chunks.remove(pos); + if (chunk != null) { + chunk.disposeMesh(); + } + } + + public Collection getChunks() { + return chunks.values(); + } + + public void shutdown() { + for (Thread thread : generationThreads) { + thread.interrupt(); + } + for (LodChunk chunk : chunks.values()) { + chunk.disposeMesh(); + } + } + + /** + * Make the chunk a bit darker, so that it can be visually distinguished from an ordinary chunk. + */ + private void tintChunk(Chunk chunk) { + for (Vector3ic pos : Chunks.CHUNK_REGION) { + chunk.setSunlight(JomlUtil.from(pos), (byte) (0.75f * chunk.getSunlight(JomlUtil.from(pos)))); + } + } + + public int getChunkLods() { + return chunkLods; + } + + private Vector3i scaleDown(Vector3ic v, int scale) { + return new Vector3i(v.x() >> scale, v.y() >> scale, v.z() >> scale); + } + + private int delay(int previous, int target) { + if (previous < target) { + return target - 1; + } else if (previous == target) { + return target; + } else { + return target + 1; + } + } + + private static class ClosenessComparator implements Comparator { + Vector3i pos; + + ClosenessComparator(Vector3i pos) { + this.pos = pos; + } + + @Override + public int compare(Vector3ic x0, Vector3ic x1) { + return Long.compare(x0.distanceSquared(pos), x1.distanceSquared(pos)); + } + } +} diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java index 48523d174d0..84b87b53e99 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java @@ -60,7 +60,8 @@ public class ChunkImpl implements Chunk { private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("0.##"); private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("#,###"); - private final Vector3i chunkPos = new Vector3i(); + protected final Vector3i chunkPos = new Vector3i(); + protected BlockRegion region; private BlockManager blockManager; @@ -74,7 +75,6 @@ public class ChunkImpl implements Chunk { private volatile TeraArray[] extraDataSnapshots; private AABBf aabb = new AABBf(); - private BlockRegion region; private boolean disposed; private boolean ready; diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/PreLodChunk.java b/engine/src/main/java/org/terasology/world/chunks/internal/PreLodChunk.java new file mode 100644 index 00000000000..02df6b334a8 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/chunks/internal/PreLodChunk.java @@ -0,0 +1,38 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.chunks.internal; + +import org.joml.Vector3i; +import org.terasology.math.JomlUtil; +import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; +import org.terasology.world.chunks.Chunks; +import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; + +/** + * A chunk that has a full set of data, but will be turned into + * a LOD chunk later. + */ +public class PreLodChunk extends ChunkImpl { + public PreLodChunk(Vector3i pos, BlockManager blockManager, ExtraBlockDataManager extraDataManager) { + super(JomlUtil.from(pos), blockManager, extraDataManager); + Vector3i min = Chunks.CHUNK_SIZE.sub(2, 4, 2, new Vector3i()).mul(pos).sub(1, 2, 1); + region = new BlockRegion(min, min.add(Chunks.CHUNK_SIZE, new Vector3i())); + } + + @Override + public int getChunkWorldOffsetX() { + return chunkPos.x * (Chunks.SIZE_X - 2) - 1; + } + + @Override + public int getChunkWorldOffsetY() { + return chunkPos.y * (Chunks.SIZE_Y - 4) - 2; + } + + @Override + public int getChunkWorldOffsetZ() { + return chunkPos.z * (Chunks.SIZE_Z - 2) - 1; + } +} diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index 90d5698a5f5..e63095b4513 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -63,6 +63,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -441,7 +442,7 @@ public void purgeWorld() { loadingPipeline = new ChunkProcessingPipeline(this::getChunk, relevanceSystem.createChunkTaskComporator()); loadingPipeline.addStage( ChunkTaskProvider.create("Chunk generate internal lightning", - InternalLightProcessor::generateInternalLighting)) + (Consumer) InternalLightProcessor::generateInternalLighting)) .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) .addStage(ChunkTaskProvider.createMulti("Light merging", chunks -> { @@ -484,7 +485,7 @@ public void setRelevanceSystem(RelevanceSystem relevanceSystem) { loadingPipeline = new ChunkProcessingPipeline(this::getChunk, relevanceSystem.createChunkTaskComporator()); loadingPipeline.addStage( ChunkTaskProvider.create("Chunk generate internal lightning", - InternalLightProcessor::generateInternalLighting)) + (Consumer) InternalLightProcessor::generateInternalLighting)) .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) .addStage(ChunkTaskProvider.createMulti("Light merging", chunks -> { diff --git a/engine/src/main/java/org/terasology/world/chunks/pipeline/ChunkProcessingPipeline.java b/engine/src/main/java/org/terasology/world/chunks/pipeline/ChunkProcessingPipeline.java index fafc5f1eccc..d13c4d9aaad 100644 --- a/engine/src/main/java/org/terasology/world/chunks/pipeline/ChunkProcessingPipeline.java +++ b/engine/src/main/java/org/terasology/world/chunks/pipeline/ChunkProcessingPipeline.java @@ -25,6 +25,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; @@ -141,6 +142,7 @@ private void onStageDone(PositionFuture future, ChunkProcessingInfo chunk chunkProcessingInfo.getPosition(), stageName), e); chunkProcessingInfo.getExternalFuture().setException(e); + } catch (CancellationException ignored) { } } @@ -258,6 +260,10 @@ public void restart() { */ public void stopProcessingAt(Vector3ic pos) { ChunkProcessingInfo removed = chunkProcessingInfoMap.remove(pos); + if (removed == null) { + return; + } + removed.getExternalFuture().cancel(true); Future currentFuture = removed.getCurrentFuture(); diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index f4041d90508..a02b64f7230 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -40,6 +40,7 @@ import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Future; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -72,7 +73,7 @@ public RemoteChunkProvider(BlockManager blockManager, LocalPlayer localPlayer) { loadingPipeline.addStage( ChunkTaskProvider.create("Chunk generate internal lightning", - InternalLightProcessor::generateInternalLighting)) + (Consumer) InternalLightProcessor::generateInternalLighting)) .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) .addStage(ChunkTaskProvider.createMulti("Light merging", chunks -> { diff --git a/engine/src/main/java/org/terasology/world/generation/BaseFacetedWorldGenerator.java b/engine/src/main/java/org/terasology/world/generation/BaseFacetedWorldGenerator.java index 0fbd72fb5bd..63936be340d 100644 --- a/engine/src/main/java/org/terasology/world/generation/BaseFacetedWorldGenerator.java +++ b/engine/src/main/java/org/terasology/world/generation/BaseFacetedWorldGenerator.java @@ -17,6 +17,7 @@ import org.terasology.engine.SimpleUri; import org.terasology.world.chunks.CoreChunk; +import org.terasology.world.generator.ScalableWorldGenerator; import org.terasology.world.generator.WorldConfigurator; import org.terasology.world.generator.WorldGenerator; import org.terasology.world.zones.Zone; @@ -26,7 +27,7 @@ /** * The most commonly used implementation of {@link WorldGenerator} based on the idea of Facets */ -public abstract class BaseFacetedWorldGenerator implements WorldGenerator { +public abstract class BaseFacetedWorldGenerator implements ScalableWorldGenerator { protected WorldBuilder worldBuilder; @@ -75,6 +76,11 @@ public void createChunk(CoreChunk chunk, EntityBuffer buffer) { world.rasterizeChunk(chunk, buffer); } + @Override + public void createChunk(CoreChunk chunk, EntityBuffer buffer, float scale) { + world.rasterizeChunk(chunk, buffer, scale); + } + @Override public WorldConfigurator getConfigurator() { if (configurator == null) { diff --git a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java index 94188e7b44f..93dc6f99a38 100644 --- a/engine/src/main/java/org/terasology/world/generation/RegionImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/RegionImpl.java @@ -17,15 +17,17 @@ public class RegionImpl implements Region, GeneratingRegion { private final BlockRegion region; private final ListMultimap, FacetProvider> facetProviderChains; private final Map, Border3D> borders; + private final float scale; private final TypeMap generatingFacets = TypeMap.create(); private final Set processedProviders = Sets.newHashSet(); private final TypeMap generatedFacets = TypeMap.create(); - public RegionImpl(BlockRegion region, ListMultimap, FacetProvider> facetProviderChains, Map, Border3D> borders) { + public RegionImpl(BlockRegion region, ListMultimap, FacetProvider> facetProviderChains, Map, Border3D> borders, float scale) { this.region = region; this.facetProviderChains = facetProviderChains; this.borders = borders; + this.scale = scale; } @Override @@ -33,7 +35,11 @@ public T getFacet(Class dataType) { T facet = generatedFacets.get(dataType); if (facet == null) { facetProviderChains.get(dataType).stream().filter(provider -> !processedProviders.contains(provider)).forEach(provider -> { - provider.process(this); + if (scale == 1) { + provider.process(this); + } else { + ((ScalableFacetProvider) provider).process(this, scale); + } processedProviders.add(provider); }); facet = generatingFacets.get(dataType); diff --git a/engine/src/main/java/org/terasology/world/generation/ScalableFacetProvider.java b/engine/src/main/java/org/terasology/world/generation/ScalableFacetProvider.java new file mode 100644 index 00000000000..561ff13c2bb --- /dev/null +++ b/engine/src/main/java/org/terasology/world/generation/ScalableFacetProvider.java @@ -0,0 +1,12 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.generation; + +public interface ScalableFacetProvider extends FacetProvider { + void process(GeneratingRegion region, float scale); + + default void process(GeneratingRegion region) { + process(region, 1); + } +} diff --git a/engine/src/main/java/org/terasology/world/generation/ScalableWorldRasterizer.java b/engine/src/main/java/org/terasology/world/generation/ScalableWorldRasterizer.java new file mode 100644 index 00000000000..9be22b107d9 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/generation/ScalableWorldRasterizer.java @@ -0,0 +1,15 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.generation; + +import org.terasology.world.chunks.CoreChunk; + +public interface ScalableWorldRasterizer extends WorldRasterizer { + void generateChunk(CoreChunk chunk, Region chunkRegion, float scale); + + @Override + default void generateChunk(CoreChunk chunk, Region chunkRegion) { + generateChunk(chunk, chunkRegion, 1); + } +} diff --git a/engine/src/main/java/org/terasology/world/generation/World.java b/engine/src/main/java/org/terasology/world/generation/World.java index 61e78acf748..0554bcdeca2 100644 --- a/engine/src/main/java/org/terasology/world/generation/World.java +++ b/engine/src/main/java/org/terasology/world/generation/World.java @@ -11,7 +11,11 @@ */ public interface World { - Region getWorldData(BlockRegion region); + Region getWorldData(BlockRegion region, float scale); + + default Region getWorldData(BlockRegion region) { + return getWorldData(region, 1); + } /** * @return the sea level, measured in blocks. May be used for setting @@ -21,6 +25,8 @@ public interface World { void rasterizeChunk(CoreChunk chunk, EntityBuffer buffer); + void rasterizeChunk(CoreChunk chunk, EntityBuffer buffer, float scale); + /** * @return a new set containing all facet classes */ diff --git a/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java b/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java index ad4302d7f55..bd9c68c285d 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldBuilder.java @@ -102,9 +102,19 @@ public World build() { for (FacetProvider provider : providersList) { provider.setSeed(seed); } - ListMultimap, FacetProvider> providerChains = determineProviderChains(); - List orderedRasterizers = ensureRasterizerOrdering(); - return new WorldImpl(providerChains, orderedRasterizers, entityProviders, determineBorders(providerChains, orderedRasterizers), seaLevel); + ListMultimap, FacetProvider> providerChains = determineProviderChains(false); + ListMultimap, FacetProvider> scalableProviderChains = determineProviderChains(true); + List orderedRasterizers = ensureRasterizerOrdering(providerChains, false); + List scalableRasterizers = ensureRasterizerOrdering(scalableProviderChains, true); + return new WorldImpl( + providerChains, + scalableProviderChains, + orderedRasterizers, + scalableRasterizers, + entityProviders, + determineBorders(providerChains, orderedRasterizers), + seaLevel + ); } private Map, Border3D> determineBorders(ListMultimap, FacetProvider> providerChains, List worldRasterizers) { @@ -170,7 +180,7 @@ private Map, Border3D> determineBorders(ListMultimap return borders; } - private ListMultimap, FacetProvider> determineProviderChains() { + private ListMultimap, FacetProvider> determineProviderChains(boolean scalable) { ListMultimap, FacetProvider> result = ArrayListMultimap.create(); Set> facets = new LinkedHashSet<>(); for (FacetProvider provider : providersList) { @@ -186,7 +196,7 @@ private ListMultimap, FacetProvider> determineProvid } } for (Class facet : facets) { - determineProviderChainFor(facet, result); + determineProviderChainFor(facet, result, scalable); if (logger.isDebugEnabled()) { StringBuilder text = new StringBuilder(facet.getSimpleName()); text.append(" --> "); @@ -204,7 +214,7 @@ private ListMultimap, FacetProvider> determineProvid return result; } - private void determineProviderChainFor(Class facet, ListMultimap, FacetProvider> result) { + private void determineProviderChainFor(Class facet, ListMultimap, FacetProvider> result, boolean scalable) { if (result.containsKey(facet)) { return; } @@ -216,19 +226,31 @@ private void determineProviderChainFor(Class facet, ListMu // first add all @Produces facet providers FacetProvider producer = null; for (FacetProvider provider : providersList) { - if (producesFacet(provider, facet)) { + if (producesFacet(provider, facet) && (!scalable || provider instanceof ScalableFacetProvider)) { if (producer != null) { logger.warn("Facet already produced by {} and overwritten by {}", producer, provider); } // add all required facets for producing provider for (Facet requirement : requiredFacets(provider)) { - determineProviderChainFor(requirement.value(), result); - orderedProviders.addAll(result.get(requirement.value())); + determineProviderChainFor(requirement.value(), result, scalable); + List requirementChain = result.get(requirement.value()); + if (requirementChain != null) { + orderedProviders.addAll(requirementChain); + } else { + facetCalculationInProgress.remove(facet); + return; + } } // add all updated facets for producing provider for (Facet updated : updatedFacets(provider)) { - determineProviderChainFor(updated.value(), result); - orderedProviders.addAll(result.get(updated.value())); + determineProviderChainFor(updated.value(), result, scalable); + List requirementChain = result.get(updated.value()); + if (requirementChain != null) { + orderedProviders.addAll(requirementChain); + } else { + facetCalculationInProgress.remove(facet); + return; + } } orderedProviders.add(provider); producer = provider; @@ -236,15 +258,25 @@ private void determineProviderChainFor(Class facet, ListMu } if (producer == null) { - logger.warn("No facet provider found that produces {}", facet); + if (!scalable) { + logger.warn("No facet provider found that produces {}", facet); + } + facetCalculationInProgress.remove(facet); + return; } // then add all @Updates facet providers - providersList.stream().filter(provider -> updatesFacet(provider, facet)).forEach(provider -> { + providersList.stream().filter(provider -> updatesFacet(provider, facet) && (!scalable || provider instanceof ScalableFacetProvider)).forEach(provider -> { + Set localOrderedProviders = Sets.newLinkedHashSet(); // add all required facets for updating provider for (Facet requirement : requiredFacets(provider)) { - determineProviderChainFor(requirement.value(), result); - orderedProviders.addAll(result.get(requirement.value())); + determineProviderChainFor(requirement.value(), result, scalable); + List requirementChain = result.get(requirement.value()); + if (requirementChain != null) { + localOrderedProviders.addAll(result.get(requirement.value())); + } else { + return; + } } // the provider updates this and other facets // just add producers for the other facets @@ -252,10 +284,15 @@ private void determineProviderChainFor(Class facet, ListMu for (FacetProvider fp : providersList) { // only add @Produces providers to avoid infinite recursion if (producesFacet(fp, updated.value())) { - orderedProviders.add(fp); + if (!scalable || fp instanceof ScalableFacetProvider) { + localOrderedProviders.add(fp); + } else { + return; + } } } } + orderedProviders.addAll(localOrderedProviders); orderedProviders.add(provider); }); result.putAll(facet, orderedProviders); @@ -301,7 +338,7 @@ private boolean updatesFacet(FacetProvider provider, Class // Ensure that rasterizers that must run after others are in the correct order. This ensures that blocks from // the dependent raterizer are not being overwritten by any antecedent rasterizer. // TODO: This will only handle first-order dependencies and does not check for circular dependencies - private List ensureRasterizerOrdering() { + private List ensureRasterizerOrdering(ListMultimap, FacetProvider> providerChains, boolean scalable) { List orderedRasterizers = Lists.newArrayList(); Set> addedRasterizers = new HashSet<>(); @@ -318,21 +355,36 @@ private List ensureRasterizerOrdering() { // Add all antecedents to the list first antecedents.forEach(dependency -> { if (!addedRasterizers.contains(dependency.getClass())) { - orderedRasterizers.add(dependency); + tryAddRasterizer(orderedRasterizers, dependency, providerChains, scalable); addedRasterizers.add(dependency.getClass()); } }); // Then add this one - orderedRasterizers.add(rasterizer); + tryAddRasterizer(orderedRasterizers, rasterizer, providerChains, scalable); } else if (!addedRasterizers.contains(rasterizer.getClass())) { - orderedRasterizers.add(rasterizer); + tryAddRasterizer(orderedRasterizers, rasterizer, providerChains, scalable); addedRasterizers.add(rasterizer.getClass()); } } return orderedRasterizers; } + private void tryAddRasterizer(List orderedRasterizers, WorldRasterizer rasterizer, ListMultimap, FacetProvider> providerChains, boolean scalable) { + if (scalable && !(rasterizer instanceof ScalableWorldRasterizer)) { + return; + } + Requires requires = rasterizer.getClass().getAnnotation(Requires.class); + if (requires != null) { + for (Facet facet : requires.value()) { + if (!providerChains.containsKey(facet.value())) { + return; + } + } + } + orderedRasterizers.add(rasterizer); + } + public FacetedWorldConfigurator createConfigurator() { List configurables = new ArrayList<>(); diff --git a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java index 3ad2055bb8c..7da5418ed97 100644 --- a/engine/src/main/java/org/terasology/world/generation/WorldImpl.java +++ b/engine/src/main/java/org/terasology/world/generation/WorldImpl.java @@ -17,26 +17,32 @@ */ public class WorldImpl implements World { private final ListMultimap, FacetProvider> facetProviderChains; + private final ListMultimap, FacetProvider> scalableFacetProviderChains; private final List worldRasterizers; + private final List scalableWorldRasterizers; private final List entityProviders; private final Map, Border3D> borders; private final int seaLevel; public WorldImpl(ListMultimap, FacetProvider> facetProviderChains, + ListMultimap, FacetProvider> scalableFacetProviderChains, List worldRasterizers, + List scalableWorldRasterizers, List entityProviders, Map, Border3D> borders, int seaLevel) { this.facetProviderChains = facetProviderChains; + this.scalableFacetProviderChains = scalableFacetProviderChains; this.worldRasterizers = worldRasterizers; + this.scalableWorldRasterizers = scalableWorldRasterizers; this.entityProviders = entityProviders; this.borders = borders; this.seaLevel = seaLevel; } @Override - public Region getWorldData(BlockRegion region) { - return new RegionImpl(region, facetProviderChains, borders); + public Region getWorldData(BlockRegion region, float scale) { + return new RegionImpl(region, scale == 1 ? facetProviderChains : scalableFacetProviderChains, borders, scale); } @Override @@ -46,7 +52,7 @@ public int getSeaLevel() { @Override public void rasterizeChunk(CoreChunk chunk, EntityBuffer buffer) { - Region chunkRegion = getWorldData(chunk.getRegion()); + Region chunkRegion = getWorldData(chunk.getRegion(), 1); for (WorldRasterizer rasterizer : worldRasterizers) { rasterizer.generateChunk(chunk, chunkRegion); } @@ -55,6 +61,17 @@ public void rasterizeChunk(CoreChunk chunk, EntityBuffer buffer) { } } + @Override + public void rasterizeChunk(CoreChunk chunk, EntityBuffer buffer, float scale) { + Region chunkRegion = getWorldData(chunk.getRegion(), scale); + for (WorldRasterizer rasterizer : scalableWorldRasterizers) { + ((ScalableWorldRasterizer) rasterizer).generateChunk(chunk, chunkRegion, scale); + } + for (EntityProvider entityProvider : entityProviders) { + entityProvider.process(chunkRegion, buffer); + } + } + @Override public Set> getAllFacets() { return Sets.newHashSet(facetProviderChains.keySet()); diff --git a/engine/src/main/java/org/terasology/world/generator/ScalableWorldGenerator.java b/engine/src/main/java/org/terasology/world/generator/ScalableWorldGenerator.java new file mode 100644 index 00000000000..8cb6b298de5 --- /dev/null +++ b/engine/src/main/java/org/terasology/world/generator/ScalableWorldGenerator.java @@ -0,0 +1,17 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.world.generator; + +import org.terasology.world.chunks.CoreChunk; +import org.terasology.world.generation.EntityBuffer; + +public interface ScalableWorldGenerator extends WorldGenerator { + /** + * Generates all contents of given chunk + * @param chunk Chunk to generate + * @param buffer Buffer to queue entities to spawn to + * @param scale The scale to generate at (larger numbers make the world's features smaller) + */ + void createChunk(CoreChunk chunk, EntityBuffer buffer, float scale); +} diff --git a/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java index 57912413ecc..c313e07a9bf 100644 --- a/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/PropagationRules.java @@ -61,9 +61,10 @@ default byte getFixedValue(Block block, Vector3i pos) { * @param existingValue The value to propagate * @param side The side the value is leaving by * @param from The block the value is leaving + * @param scale The scale of the chunk * @return The new value to set at the block position */ - byte propagateValue(byte existingValue, Side side, Block from); + byte propagateValue(byte existingValue, Side side, Block from, int scale); /** * @return The maximum value possible for this data diff --git a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java index 811d3d4f4d9..59e89727f80 100644 --- a/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/StandardBatchPropagator.java @@ -28,6 +28,7 @@ public class StandardBatchPropagator implements BatchPropagator { private PropagationRules rules; private PropagatorWorldView world; + private int scale; /* Queues are stored in reverse order. Ie, strongest light is 0. */ private Set[] reduceQueues; @@ -36,8 +37,13 @@ public class StandardBatchPropagator implements BatchPropagator { private Map chunkEdgeDeltas = Maps.newEnumMap(Side.class); public StandardBatchPropagator(PropagationRules rules, PropagatorWorldView world) { + this(rules, world, 1); + } + + public StandardBatchPropagator(PropagationRules rules, PropagatorWorldView world, int scale) { this.world = world; this.rules = rules; + this.scale = scale; for (Side side : Side.getAllSides()) { Vector3i delta = new Vector3i(side.direction()); @@ -116,7 +122,7 @@ private void reviewChange(BlockChange blockChange) { reduce(blockChangePosition, existingValue); side.getAdjacentPos(blockChangePosition, adjPos); byte adjValue = world.getValueAt(adjPos); - if (adjValue == rules.propagateValue(existingValue, side, blockChange.getFrom())) { + if (adjValue == rules.propagateValue(existingValue, side, blockChange.getFrom(), scale)) { reduce(adjPos, adjValue); } @@ -157,7 +163,7 @@ private void purge(Vector3ic pos, byte oldValue) { Vector3i adjPos = new Vector3i(); for (Side side : Side.getAllSides()) { /* Handle this value being reset to the default by updating sides as needed */ - byte expectedValue = rules.propagateValue(oldValue, side, block); + byte expectedValue = rules.propagateValue(oldValue, side, block, scale); if (rules.canSpreadOutOf(block, side)) { side.getAdjacentPos(pos, adjPos); byte adjValue = world.getValueAt(adjPos); @@ -225,7 +231,7 @@ private void push(Vector3ic pos, byte value) { Block block = world.getBlockAt(pos); Vector3i adjPos = new Vector3i(); for (Side side : Side.getAllSides()) { - byte propagatedValue = rules.propagateValue(value, side, block); + byte propagatedValue = rules.propagateValue(value, side, block, scale); if (rules.canSpreadOutOf(block, side)) { side.getAdjacentPos(pos, adjPos); diff --git a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java index db4d450a67a..f78d6d2ef07 100644 --- a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java @@ -141,7 +141,7 @@ private void push(Vector3ic pos, byte value) { Block block = regenWorld.getBlockAt(pos); Vector3i position = new Vector3i(pos); while (regenRules.canSpreadOutOf(block, Side.BOTTOM)) { - regenValue = regenRules.propagateValue(regenValue, Side.BOTTOM, block); + regenValue = regenRules.propagateValue(regenValue, Side.BOTTOM, block, 1); position.y -= 1; byte adjValue = regenWorld.getValueAt(position); if (adjValue < regenValue && adjValue != PropagatorWorldView.UNAVAILABLE) { diff --git a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java index f68a57a3617..da3c18fd46b 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/InternalLightProcessor.java @@ -39,9 +39,13 @@ private InternalLightProcessor() { } public static void generateInternalLighting(LitChunk chunk) { - populateSunlightRegen(chunk); - populateSunlight(chunk); - populateLight(chunk); + generateInternalLighting(chunk, 1); + } + + public static void generateInternalLighting(LitChunk chunk, int scale) { + populateSunlightRegen(chunk, scale); + populateSunlight(chunk, scale); + populateLight(chunk, scale); } /** @@ -49,8 +53,8 @@ public static void generateInternalLighting(LitChunk chunk) { * * @param chunk The chunk to populate through */ - private static void populateLight(LitChunk chunk) { - BatchPropagator lightPropagator = new StandardBatchPropagator(LIGHT_RULES, new SingleChunkView(LIGHT_RULES, chunk)); + private static void populateLight(LitChunk chunk, int scale) { + BatchPropagator lightPropagator = new StandardBatchPropagator(LIGHT_RULES, new SingleChunkView(LIGHT_RULES, chunk), scale); Vector3i pos = new Vector3i(); for (int x = 0; x < Chunks.SIZE_X; x++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { @@ -71,15 +75,15 @@ private static void populateLight(LitChunk chunk) { * * @param chunk The chunk to set in */ - private static void populateSunlight(LitChunk chunk) { + private static void populateSunlight(LitChunk chunk, int scale) { PropagationRules sunlightRules = new SunlightPropagationRules(chunk); - BatchPropagator lightPropagator = new StandardBatchPropagator(sunlightRules, new SingleChunkView(sunlightRules, chunk)); + BatchPropagator lightPropagator = new StandardBatchPropagator(sunlightRules, new SingleChunkView(sunlightRules, chunk), scale); Vector3i pos = new Vector3i(); for (int x = 0; x < Chunks.SIZE_X; x++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { /* Start at the bottom of the chunk and then move up until the max sunlight level */ - for (int y = 0; y < Chunks.MAX_SUNLIGHT; y++) { + for (int y = 0; y < Chunks.SIZE_Y; y++) { pos.set(x, y, z); Block block = chunk.getBlock(x, y, z); byte light = sunlightRules.getFixedValue(block, pos); @@ -98,18 +102,18 @@ private static void populateSunlight(LitChunk chunk) { * * @param chunk The chunk to populate the regeneration values through */ - private static void populateSunlightRegen(LitChunk chunk) { + private static void populateSunlightRegen(LitChunk chunk, int scale) { int top = Chunks.SIZE_Y - 1; /* Scan through each column in the chunk & propagate light from the top down */ for (int x = 0; x < Chunks.SIZE_X; x++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { - byte regen = 0; + byte regen = chunk.getSunlightRegen(x, top, z); Block lastBlock = chunk.getBlock(x, top, z); for (int y = top - 1; y >= 0; y--) { Block block = chunk.getBlock(x, y, z); /* If the regeneration can propagate down into this block */ if (SUNLIGHT_REGEN_RULES.canSpreadOutOf(lastBlock, Side.BOTTOM) && SUNLIGHT_REGEN_RULES.canSpreadInto(block, Side.TOP)) { - regen = SUNLIGHT_REGEN_RULES.propagateValue(regen, Side.BOTTOM, lastBlock); + regen = SUNLIGHT_REGEN_RULES.propagateValue(regen, Side.BOTTOM, lastBlock, scale); chunk.setSunlightRegen(x, y, z, regen); } else { regen = 0; diff --git a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java index 4741edcbc51..461b4938c5e 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java @@ -44,8 +44,8 @@ public byte getFixedValue(Block block, Vector3ic pos) { * {@inheritDoc} */ @Override - public byte propagateValue(byte existingValue, Side side, Block from) { - return (byte) (existingValue - 1); + public byte propagateValue(byte existingValue, Side side, Block from, int scale) { + return (byte) Math.max(existingValue - scale, 0); } /** diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java index 23952337ce9..d50541fd8ef 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java @@ -56,8 +56,8 @@ public byte getFixedValue(Block block, Vector3ic pos) { * {@inheritDoc} */ @Override - public byte propagateValue(byte existingValue, Side side, Block from) { - return (byte) Math.max(existingValue - 1, 0); + public byte propagateValue(byte existingValue, Side side, Block from, int scale) { + return (byte) Math.max(existingValue - scale, 0); } /** diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java index 5c93781a486..a663c2858cf 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java @@ -45,9 +45,9 @@ public byte getFixedValue(Block block, Vector3ic pos) { * {@inheritDoc} */ @Override - public byte propagateValue(byte existingValue, Side side, Block from) { + public byte propagateValue(byte existingValue, Side side, Block from, int scale) { if (side == Side.BOTTOM) { - return (existingValue == Chunks.MAX_SUNLIGHT_REGEN) ? Chunks.MAX_SUNLIGHT_REGEN : (byte) (existingValue + 1); + return (byte) Math.min(Chunks.MAX_SUNLIGHT_REGEN, existingValue + scale); } return 0; } diff --git a/engine/src/main/resources/assets/i18n/menu.lang b/engine/src/main/resources/assets/i18n/menu.lang index 403cb143d3e..8bbef966eae 100644 --- a/engine/src/main/resources/assets/i18n/menu.lang +++ b/engine/src/main/resources/assets/i18n/menu.lang @@ -80,6 +80,7 @@ "category-nui": "category-nui", "change-keybind-popup-message": "change-keybind-popup-message", "change-keybind-popup-title": "change-keybind-popup-title", + "chunk-lods": "chunk-lods", "clamp-lighting": "clamp-lighting", "cloud-shadows": "cloud-shadows", "config": "config", diff --git a/engine/src/main/resources/assets/i18n/menu_en.lang b/engine/src/main/resources/assets/i18n/menu_en.lang index 3b243c704f6..4117a0f6509 100644 --- a/engine/src/main/resources/assets/i18n/menu_en.lang +++ b/engine/src/main/resources/assets/i18n/menu_en.lang @@ -81,6 +81,7 @@ "category-nui": "NUI", "change-keybind-popup-message": "is already bound to an action. Rebind anyway?", "change-keybind-popup-title": "Key already bound", + "chunk-lods": "Chunk LODs", "clamp-lighting": "Clamp Lighting", "cloud-shadows": "Cloud Shadows", "config": "Configure", diff --git a/engine/src/main/resources/assets/ui/menu/videoMenuScreen.ui b/engine/src/main/resources/assets/ui/menu/videoMenuScreen.ui index 47dfa93ca89..614504b7270 100644 --- a/engine/src/main/resources/assets/ui/menu/videoMenuScreen.ui +++ b/engine/src/main/resources/assets/ui/menu/videoMenuScreen.ui @@ -222,6 +222,14 @@ "text": "${engine:menu#reset-fov-amount}", "id": "fovReset" }, + { + "type": "UILabel", + "text": "${engine:menu#chunk-lods}: " + }, + { + "type": "UISlider", + "id": "chunkLods" + }, { "type": "UILabel", "text": "${engine:menu#framerate-limit}: " From ac6ba09e55ba5ccfffc927d305498e0dad638951 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 10:30:12 -0800 Subject: [PATCH 184/259] feat(JOML): migrate MeshBuilder (#4446) --- .../assets/font/FontMeshBuilder.java | 2 +- .../rendering/assets/mesh/MeshBuilder.java | 61 ++----------------- .../nui/internal/LwjglCanvasRenderer.java | 9 ++- 3 files changed, 10 insertions(+), 62 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/assets/font/FontMeshBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/font/FontMeshBuilder.java index 0879d217bbd..4582c7a63da 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/font/FontMeshBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/font/FontMeshBuilder.java @@ -16,7 +16,7 @@ package org.terasology.rendering.assets.font; import com.google.common.collect.Maps; -import org.terasology.math.geom.Vector3f; +import org.joml.Vector3f; import org.terasology.nui.Colorc; import org.terasology.nui.HorizontalAlign; import org.terasology.nui.FontColor; diff --git a/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java b/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java index 91b897b844e..2848ff66dc8 100644 --- a/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java +++ b/engine/src/main/java/org/terasology/rendering/assets/mesh/MeshBuilder.java @@ -16,10 +16,9 @@ package org.terasology.rendering.assets.mesh; import org.joml.Vector2fc; +import org.joml.Vector3f; import org.joml.Vector3fc; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; import org.terasology.module.sandbox.API; import org.terasology.nui.Colorc; import org.terasology.utilities.Assets; @@ -76,21 +75,6 @@ public class MeshBuilder { private int vertexCount; private TextureMapper textureMapper; - /** - * - * @param v - * @return - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #addVertex(Vector3fc)}. - */ - public MeshBuilder addVertex(Vector3f v) { - meshData.getVertices().add(v.x); - meshData.getVertices().add(v.y); - meshData.getVertices().add(v.z); - vertexCount++; - return this; - } - public MeshBuilder addVertex(Vector3fc v) { meshData.getVertices().add(v.x()); meshData.getVertices().add(v.y()); @@ -99,29 +83,6 @@ public MeshBuilder addVertex(Vector3fc v) { return this; } - /** - * - * @param v1 - * @param v2 - * @param v3 - * @param vn - * @return - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #addPoly(Vector3fc, Vector3fc, Vector3fc, Vector3fc...)}. - */ - public MeshBuilder addPoly(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f... vn) { - for (int i = 0; i < vn.length + 1; i++) { - addIndices(vertexCount, vertexCount + i + 2, vertexCount + i + 1); - } - addVertex(v1); - addVertex(v2); - addVertex(v3); - for (Vector3f v : vn) { - addVertex(v); - } - return this; - } - /** * * @param v1 @@ -163,18 +124,6 @@ public MeshBuilder addTexCoord(float x, float y) { return this; } - /** - * - * @param v - * @return - * - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #addTexCoord(Vector2fc)}. - */ - public MeshBuilder addTexCoord(Vector2f v) { - return addTexCoord(v.x, v.y); - } - public MeshBuilder addTexCoord(Vector2fc v) { return addTexCoord(v.x(), v.y()); } @@ -206,11 +155,11 @@ public Mesh build(ResourceUrn urn) { *

    * Use the texture mapper to change how texture coordinates (u and v) are applied to each vertex. */ - public MeshBuilder addBox(org.joml.Vector3f offset, org.joml.Vector3f size, float u, float v) { + public MeshBuilder addBox(Vector3fc offset, Vector3fc size, float u, float v) { int vertexId = vertexCount; textureMapper.initialize(offset, size); for (int i = 0; i < VERTICES.length / 3; i++) { - addVertex(new Vector3f(offset.x + size.x * VERTICES[i * 3], offset.y + size.y * VERTICES[i * 3 + 1], offset.z + size.z * VERTICES[i * 3 + 2])); + addVertex(new Vector3f(offset.x() + size.x() * VERTICES[i * 3], offset.y() + size.y() * VERTICES[i * 3 + 1], offset.z() + size.z() * VERTICES[i * 3 + 2])); addTexCoord(textureMapper.map(i, u, v)); } for (int i : INDICES) { @@ -225,8 +174,8 @@ public void setTextureMapper(TextureMapper textureMapper) { @API public interface TextureMapper { - void initialize(org.joml.Vector3f offset, org.joml.Vector3f size); + void initialize(Vector3fc offset, Vector3fc size); - org.joml.Vector2fc map(int vertexIndex, float u, float v); + Vector2fc map(int vertexIndex, float u, float v); } } diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java index 86e686941a4..b401e207706 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/LwjglCanvasRenderer.java @@ -8,9 +8,6 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Quaternionfc; -import org.terasology.joml.geom.AABBfc; -import org.terasology.joml.geom.Rectanglef; -import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2f; import org.joml.Vector2ic; import org.joml.Vector3f; @@ -23,7 +20,9 @@ import org.terasology.config.RenderingConfig; import org.terasology.context.Context; import org.terasology.engine.subsystem.DisplayDevice; -import org.terasology.math.AABB; +import org.terasology.joml.geom.AABBfc; +import org.terasology.joml.geom.Rectanglef; +import org.terasology.joml.geom.Rectanglei; import org.terasology.math.JomlUtil; import org.terasology.math.TeraMath; import org.terasology.math.geom.Vector2i; @@ -501,7 +500,7 @@ public void setUiScale(float uiScale) { } private void addRectPoly(MeshBuilder builder, float minX, float minY, float maxX, float maxY, float texMinX, float texMinY, float texMaxX, float texMaxY) { - builder.addPoly(JomlUtil.from(new Vector3f(minX, minY, 0)), JomlUtil.from(new Vector3f(maxX, minY, 0)), JomlUtil.from(new Vector3f(maxX, maxY, 0)), JomlUtil.from(new Vector3f(minX, maxY, 0))); + builder.addPoly(new Vector3f(minX, minY, 0), new Vector3f(maxX, minY, 0), new Vector3f(maxX, maxY, 0), new Vector3f(minX, maxY, 0)); builder.addTexCoord(texMinX, texMinY); builder.addTexCoord(texMaxX, texMinY); builder.addTexCoord(texMaxX, texMaxY); From 07aa60d4d1a648c0b6f0ff4ad0b7035ea3f3843c Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 10:46:52 -0800 Subject: [PATCH 185/259] feat(JOML): cleanup chunk mesh (#4450) --- .../rendering/primitives/ChunkMesh.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/primitives/ChunkMesh.java b/engine/src/main/java/org/terasology/rendering/primitives/ChunkMesh.java index ceefb101aea..2dcbe04b038 100644 --- a/engine/src/main/java/org/terasology/rendering/primitives/ChunkMesh.java +++ b/engine/src/main/java/org/terasology/rendering/primitives/ChunkMesh.java @@ -20,16 +20,16 @@ import gnu.trove.list.TIntList; import gnu.trove.list.array.TFloatArrayList; import gnu.trove.list.array.TIntArrayList; +import org.joml.Vector3f; import org.joml.Vector3fc; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL15; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; -import org.terasology.math.geom.Vector3f; import org.terasology.module.sandbox.API; import org.terasology.rendering.VertexBufferObjectUtil; import org.terasology.rendering.assets.material.Material; -import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import java.nio.IntBuffer; import java.util.Map; @@ -235,9 +235,9 @@ private void renderVbo(int id) { */ public void updateMaterial(Material chunkMaterial, Vector3fc chunkPosition, boolean chunkIsAnimated) { chunkMaterial.setFloat3("chunkPositionWorld", - chunkPosition.x() * ChunkConstants.SIZE_X, - chunkPosition.y() * ChunkConstants.SIZE_Y, - chunkPosition.z() * ChunkConstants.SIZE_Z, + chunkPosition.x() * Chunks.SIZE_X, + chunkPosition.y() * Chunks.SIZE_Y, + chunkPosition.z() * Chunks.SIZE_Z, true); chunkMaterial.setFloat("animated", chunkIsAnimated ? 1.0f : 0.0f, true); } @@ -256,9 +256,9 @@ public int render(ChunkMesh.RenderPhase phase, Vector3fc chunkPosition, Vector3f // chunkPositionRelativeToCamera = chunkCoordinates * chunkDimensions - cameraCoordinate final Vector3f chunkPositionRelativeToCamera = - new Vector3f(chunkPosition.x() * ChunkConstants.SIZE_X - cameraPosition.x(), - chunkPosition.y() * ChunkConstants.SIZE_Y - cameraPosition.y(), - chunkPosition.z() * ChunkConstants.SIZE_Z - cameraPosition.z()); + new Vector3f(chunkPosition.x() * Chunks.SIZE_X - cameraPosition.x(), + chunkPosition.y() * Chunks.SIZE_Y - cameraPosition.y(), + chunkPosition.z() * Chunks.SIZE_Z - cameraPosition.z()); GL11.glTranslatef(chunkPositionRelativeToCamera.x, chunkPositionRelativeToCamera.y, chunkPositionRelativeToCamera.z); render(phase); // this is where the chunk is actually rendered From 371f8eb644c2d39fe1a9e606a45d27fabdf5ab05 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 11:03:44 -0800 Subject: [PATCH 186/259] feat(JOML): remove deprecated methods from OnBlockItemPlaced (#4447) --- .../world/block/items/OnBlockItemPlaced.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java b/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java index 36ecf90ef74..6b81432604b 100644 --- a/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java +++ b/engine/src/main/java/org/terasology/world/block/items/OnBlockItemPlaced.java @@ -6,7 +6,6 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.Event; -import org.terasology.math.JomlUtil; /** * This event gets called whenever a block item is placed in the world @@ -27,27 +26,6 @@ public class OnBlockItemPlaced implements Event { */ private EntityRef instigator = EntityRef.NULL; - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #OnBlockItemPlaced(Vector3ic, EntityRef, EntityRef)}. - */ - @Deprecated - public OnBlockItemPlaced(org.terasology.math.geom.Vector3i pos, EntityRef placedBlock) { - this.position = JomlUtil.from(pos); - this.placedBlock = placedBlock; - } - - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #OnBlockItemPlaced(Vector3ic, EntityRef, EntityRef)}. - */ - @Deprecated - public OnBlockItemPlaced(org.terasology.math.geom.Vector3i pos, EntityRef placedBlock, EntityRef instigator) { - this.position = JomlUtil.from(pos); - this.placedBlock = placedBlock; - this.instigator = instigator; - } - /** * * @param pos the position that the block is placed From bc76426cada2d07cf42b0930dcbe177476f592e8 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 11:47:55 -0800 Subject: [PATCH 187/259] feat(JOML): migrate logic for LitChunk (#4449) --- .../generator/InternalLightGeneratorTest.java | 58 +++++----- .../BetweenChunkPropagationTest.java | 36 ++++--- .../terasology/math/Diamond3iIterator.java | 100 ------------------ .../org/terasology/world/chunks/LitChunk.java | 14 +-- .../org/terasology/world/chunks/LodChunk.java | 12 +-- .../world/chunks/LodChunkProvider.java | 2 +- .../world/chunks/internal/ChunkImpl.java | 12 +-- .../world/internal/ChunkViewCoreImpl.java | 8 +- .../world/internal/WorldProviderCoreImpl.java | 6 +- .../SunlightRegenBatchPropagator.java | 4 +- .../light/LightPropagationRules.java | 3 +- .../propagation/light/LightWorldView.java | 5 +- .../light/SunlightPropagationRules.java | 3 +- .../light/SunlightRegenPropagationRules.java | 2 +- .../light/SunlightRegenWorldView.java | 4 +- .../propagation/light/SunlightWorldView.java | 5 +- 16 files changed, 87 insertions(+), 187 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/math/Diamond3iIterator.java diff --git a/engine-tests/src/test/java/org/terasology/world/generator/InternalLightGeneratorTest.java b/engine-tests/src/test/java/org/terasology/world/generator/InternalLightGeneratorTest.java index b6cfa7389fa..c565436cb18 100644 --- a/engine-tests/src/test/java/org/terasology/world/generator/InternalLightGeneratorTest.java +++ b/engine-tests/src/test/java/org/terasology/world/generator/InternalLightGeneratorTest.java @@ -15,17 +15,18 @@ */ package org.terasology.world.generator; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.terasology.TerasologyTestingEnvironment; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; -import org.terasology.math.Diamond3iIterator; -import org.terasology.math.Region3i; -import org.terasology.math.geom.Vector3i; +import org.terasology.math.Diamond3iIterable; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockUri; import org.terasology.world.block.family.SymmetricFamily; import org.terasology.world.block.internal.BlockManagerImpl; @@ -35,6 +36,7 @@ import org.terasology.world.block.tiles.NullWorldAtlas; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; import org.terasology.world.propagation.light.InternalLightProcessor; @@ -84,8 +86,8 @@ public void testUnblockedSunlightRegenPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z))) { - byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0,0,0).setSize(Chunks.SIZE_X, Chunks.SIZE_Y, Chunks.SIZE_Z)) { + byte expectedRegen = (byte) Math.min(Chunks.SIZE_Y - pos.y() - 1, Chunks.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } } @@ -93,20 +95,20 @@ public void testUnblockedSunlightRegenPropagation() { @Test public void testBlockedSunlightRegenPropagationResets() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 60, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 60, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 61, 0), new Vector3i(ChunkConstants.SIZE_X, 3, ChunkConstants.SIZE_Z))) { - byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0, 61, 0).setSize(Chunks.SIZE_X, 3, Chunks.SIZE_Z)) { + byte expectedRegen = (byte) Math.min(Chunks.SIZE_Y - pos.y() - 1, Chunks.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 60, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 60, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { assertEquals(0, chunk.getSunlightRegen(pos)); } - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 59, ChunkConstants.SIZE_Z))) { - byte expectedRegen = (byte) Math.min(60 - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 59, Chunks.SIZE_Z)) { + byte expectedRegen = (byte) Math.min(60 - pos.y() - 1, Chunks.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } } @@ -114,13 +116,13 @@ public void testBlockedSunlightRegenPropagationResets() { @Test public void testBlockedAtTopSunlightRegenPropagationResets() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 63, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 63, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - 1, ChunkConstants.SIZE_Z))) { - byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 2, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0,0,0).setSize(Chunks.SIZE_X, Chunks.SIZE_Y - 1, Chunks.SIZE_Z)) { + byte expectedRegen = (byte) Math.min(Chunks.SIZE_Y - pos.y() - 2, Chunks.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } } @@ -130,14 +132,14 @@ public void testUnblockedSunlightPropagationAfterHittingMaxRegen() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 15, 0), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - 15, - ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 15, 0).setSize(Chunks.SIZE_X, Chunks.SIZE_Y - 15, + Chunks.SIZE_Z)) { assertEquals(0, chunk.getSunlight(pos)); } - for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - ChunkConstants.MAX_SUNLIGHT_REGEN, - ChunkConstants.SIZE_Z))) { - byte expectedSunlight = (byte) Math.min(ChunkConstants.SIZE_Y - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD - pos.y - 1, ChunkConstants.MAX_SUNLIGHT); + for (Vector3ic pos : new BlockRegion(0,0,0).setSize(Chunks.SIZE_X, Chunks.SIZE_Y - Chunks.MAX_SUNLIGHT_REGEN, + Chunks.SIZE_Z)) { + byte expectedSunlight = (byte) Math.min(Chunks.SIZE_Y - Chunks.SUNLIGHT_REGEN_THRESHOLD - pos.y() - 1, Chunks.MAX_SUNLIGHT); assertEquals(expectedSunlight, chunk.getSunlight(pos), () -> "Incorrect lighting at " + pos); } } @@ -145,13 +147,13 @@ public void testUnblockedSunlightPropagationAfterHittingMaxRegen() { @Test public void testBlockedSunlightPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 4, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 4, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 5, - ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 5, + Chunks.SIZE_Z)) { assertEquals(0, chunk.getSunlight(pos), () -> "Incorrect lighting at " + pos); } } @@ -161,16 +163,16 @@ public void testUnblockedSunlightPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 15, - ChunkConstants.SIZE_Z))) { - assertEquals(15 - pos.y, chunk.getSunlight(pos), () -> "Incorrect lighting at " + pos); + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 15, + Chunks.SIZE_Z)) { + assertEquals(15 - pos.y(), chunk.getSunlight(pos), () -> "Incorrect lighting at " + pos); } } @Test public void testHorizontalSunlightPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, extraDataManager); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 4, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 4, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { chunk.setBlock(pos, solidBlock); } chunk.setBlock(new Vector3i(16, 4, 16), airBlock); @@ -195,9 +197,9 @@ public void testLightPropagation() { InternalLightProcessor.generateInternalLighting(chunk); assertEquals(fullLight.getLuminance(), chunk.getLight(16, 32, 16)); - assertEquals(fullLight.getLuminance() - 1, chunk.getLight(new Vector3i(16, 33, 16))); + assertEquals(fullLight.getLuminance() - 1, chunk.getLight(16, 33, 16)); for (int i = 1; i < fullLight.getLuminance(); ++i) { - for (Vector3i pos : Diamond3iIterator.iterateAtDistance(new Vector3i(16, 32, 16), i)) { + for (Vector3ic pos : Diamond3iIterable.shell(new Vector3i(16, 32, 16), i).build()) { assertEquals(fullLight.getLuminance() - i, chunk.getLight(pos)); } } diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java index 69903278642..670d2a1836e 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java @@ -30,6 +30,7 @@ import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; +import org.terasology.world.block.BlockRegion; import org.terasology.world.block.BlockUri; import org.terasology.world.block.family.SymmetricFamily; import org.terasology.world.block.internal.BlockManagerImpl; @@ -40,6 +41,7 @@ import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.internal.ChunkImpl; import org.terasology.world.internal.ChunkViewCore; @@ -105,17 +107,17 @@ public void testBetweenChunksSimple() { provider.addChunk(topChunk); provider.addChunk(bottomChunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { - topChunk.setSunlight(pos, ChunkConstants.MAX_SUNLIGHT); - topChunk.setSunlightRegen(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { + topChunk.setSunlight(pos, Chunks.MAX_SUNLIGHT); + topChunk.setSunlightRegen(pos, Chunks.MAX_SUNLIGHT_REGEN); } InternalLightProcessor.generateInternalLighting(bottomChunk); propagator.propagateBetween(topChunk, bottomChunk, Side.BOTTOM, true); propagator.process(); sunlightPropagator.process(); - for (Vector3i pos : ChunkConstants.CHUNK_REGION) { - assertEquals(ChunkConstants.MAX_SUNLIGHT, bottomChunk.getSunlight(pos), () -> "Incorrect at position " + pos); - assertEquals(ChunkConstants.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos), () -> "Incorrect at position " + pos); + for (Vector3ic pos : Chunks.CHUNK_REGION) { + assertEquals(Chunks.MAX_SUNLIGHT, bottomChunk.getSunlight(pos), () -> "Incorrect at position " + pos); + assertEquals(Chunks.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos), () -> "Incorrect at position " + pos); } } @@ -127,15 +129,15 @@ public void testBetweenChunksSimpleSunlightRegenOnly() { provider.addChunk(topChunk); provider.addChunk(bottomChunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { - topChunk.setSunlight(pos, ChunkConstants.MAX_SUNLIGHT); - topChunk.setSunlightRegen(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { + topChunk.setSunlight(pos, Chunks.MAX_SUNLIGHT); + topChunk.setSunlightRegen(pos, Chunks.MAX_SUNLIGHT_REGEN); } InternalLightProcessor.generateInternalLighting(bottomChunk); propagator.propagateBetween(topChunk, bottomChunk, Side.BOTTOM, true); propagator.process(); - for (Vector3i pos : ChunkConstants.CHUNK_REGION) { - assertEquals(ChunkConstants.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos), () -> "Incorrect at position " + pos); + for (Vector3ic pos : Chunks.CHUNK_REGION) { + assertEquals(Chunks.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos), () -> "Incorrect at position " + pos); } } @@ -147,11 +149,11 @@ public void testBetweenChunksWithOverhang() { provider.addChunk(topChunk); provider.addChunk(bottomChunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { - topChunk.setSunlight(pos, ChunkConstants.MAX_SUNLIGHT); - topChunk.setSunlightRegen(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { + topChunk.setSunlight(pos, Chunks.MAX_SUNLIGHT); + topChunk.setSunlightRegen(pos, Chunks.MAX_SUNLIGHT_REGEN); } - for (Vector3i pos : Region3i.createFromMinMax(new Vector3i(16, 48, 0), new Vector3i(31, 48, 31))) { + for (Vector3ic pos : new BlockRegion(16, 48, 0, 31, 48, 31)) { bottomChunk.setBlock(pos, solid); } InternalLightProcessor.generateInternalLighting(bottomChunk); @@ -175,11 +177,11 @@ public void testPropagateSunlightAppearingMidChunk() { provider.addChunk(topChunk); provider.addChunk(bottomChunk); - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { + for (Vector3ic pos : new BlockRegion(0, 0, 0).setSize(Chunks.SIZE_X, 1, Chunks.SIZE_Z)) { topChunk.setSunlight(pos, (byte) 0); topChunk.setSunlightRegen(pos, (byte) 0); } - for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(8, 0, 8), new Vector3i(ChunkConstants.SIZE_X - 16, 1, ChunkConstants.SIZE_Z - 16))) { + for (Vector3ic pos : new BlockRegion(8, 0, 8).setSize(Chunks.SIZE_X- 16, 1, Chunks.SIZE_Z- 16)) { topChunk.setSunlight(pos, (byte) 0); topChunk.setSunlightRegen(pos, (byte) 32); } diff --git a/engine/src/main/java/org/terasology/math/Diamond3iIterator.java b/engine/src/main/java/org/terasology/math/Diamond3iIterator.java deleted file mode 100644 index 04a99f2dd04..00000000000 --- a/engine/src/main/java/org/terasology/math/Diamond3iIterator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.math; - -import org.terasology.math.geom.Vector3i; - -import java.util.Iterator; - -/** - * @deprecated this class is schedules for removal in an upcoming version - * Use the JOML implementation instead: {@link Diamond3iIterable} - **/ -@Deprecated -public final class Diamond3iIterator implements Iterator { - - private final Vector3i origin; - private final int maxDistance; - - private int x; - private int y; - private int z; - private int level; - - private Diamond3iIterator(Vector3i origin, int maxDistance) { - this.origin = origin; - this.maxDistance = maxDistance + 1; - } - - private Diamond3iIterator(Vector3i origin, int maxDistance, int startDistance) { - this(origin, maxDistance); - this.level = startDistance + 1; - x = -level; - } - - public static Iterable iterate(final Vector3i origin, final int distance) { - return () -> new Diamond3iIterator(origin, distance); - } - - public static Iterable iterate(final Vector3i origin, final int distance, final int startDistance) { - return () -> new Diamond3iIterator(origin, distance, startDistance); - } - - public static Iterable iterateAtDistance(final Vector3i origin, final int distance) { - return () -> new Diamond3iIterator(origin, distance, distance - 1); - } - - @Override - public boolean hasNext() { - return level < maxDistance; - } - - @Override - public Vector3i next() { - Vector3i result = new Vector3i(origin.x + x, origin.y + y, origin.z + z); - if (z < 0) { - z *= -1; - } else if (y < 0) { - y *= -1; - z = -(level - TeraMath.fastAbs(x) - TeraMath.fastAbs(y)); - } else { - y = -y + 1; - if (y > 0) { - if (++x <= level) { - y = TeraMath.fastAbs(x) - level; - z = 0; - } else { - level++; - x = -level; - y = 0; - z = 0; - } - } else { - z = -(level - TeraMath.fastAbs(x) - TeraMath.fastAbs(y)); - } - } - - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - -} diff --git a/engine/src/main/java/org/terasology/world/chunks/LitChunk.java b/engine/src/main/java/org/terasology/world/chunks/LitChunk.java index 1cfb74822ac..73477171dab 100644 --- a/engine/src/main/java/org/terasology/world/chunks/LitChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/LitChunk.java @@ -15,7 +15,7 @@ */ package org.terasology.world.chunks; -import org.terasology.math.geom.BaseVector3i; +import org.joml.Vector3ic; import org.terasology.module.sandbox.API; /** @@ -34,7 +34,7 @@ public interface LitChunk extends CoreChunk { * @param pos Position of the block relative to corner of the chunk * @return Current sunlight */ - byte getSunlight(BaseVector3i pos); + byte getSunlight(Vector3ic pos); /** * Returns the current amount of sunlight at given position relative to the chunk. @@ -53,7 +53,7 @@ public interface LitChunk extends CoreChunk { * @param amount Amount of sunlight to set this block to * @return False if the amount is same as the old value, true otherwise */ - boolean setSunlight(BaseVector3i pos, byte amount); + boolean setSunlight(Vector3ic pos, byte amount); /** * Sets the amount of sunlight at given position relative to the chunk. @@ -71,7 +71,7 @@ public interface LitChunk extends CoreChunk { * @param pos Position of the block relative to corner of the chunk * @return Current sunlight regeneration */ - byte getSunlightRegen(BaseVector3i pos); + byte getSunlightRegen(Vector3ic pos); /** * Returns current value of sunlight regeneration for given block relative to the chunk. @@ -90,7 +90,7 @@ public interface LitChunk extends CoreChunk { * @param amount Sunlight regeneration amount * @return False if the amount is same as the old value, true otherwise */ - boolean setSunlightRegen(BaseVector3i pos, byte amount); + boolean setSunlightRegen(Vector3ic pos, byte amount); /** * Sets sunlight regeneration for given block relative to the chunk. @@ -109,7 +109,7 @@ public interface LitChunk extends CoreChunk { * @param pos Position of the block relative to corner of the chunk * @return Current lightness */ - byte getLight(BaseVector3i pos); + byte getLight(Vector3ic pos); /** * Returns current amount of light for given block relative to the chunk. @@ -128,7 +128,7 @@ public interface LitChunk extends CoreChunk { * @param amount Lightness value * @return False if the amount is same as the old value, true otherwise */ - boolean setLight(BaseVector3i pos, byte amount); + boolean setLight(Vector3ic pos, byte amount); /** * Sets lightness for given block relative to the chunk. diff --git a/engine/src/main/java/org/terasology/world/chunks/LodChunk.java b/engine/src/main/java/org/terasology/world/chunks/LodChunk.java index ffdb7cc224c..2299ccd887c 100644 --- a/engine/src/main/java/org/terasology/world/chunks/LodChunk.java +++ b/engine/src/main/java/org/terasology/world/chunks/LodChunk.java @@ -238,7 +238,7 @@ public ChunkBlockIterator getBlockIterator() { } @Override - public byte getSunlight(BaseVector3i pos) { + public byte getSunlight(Vector3ic pos) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } @@ -248,7 +248,7 @@ public byte getSunlight(int x, int y, int z) { } @Override - public boolean setSunlight(BaseVector3i pos, byte amount) { + public boolean setSunlight(Vector3ic pos, byte amount) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } @@ -258,7 +258,7 @@ public boolean setSunlight(int x, int y, int z, byte amount) { } @Override - public byte getSunlightRegen(BaseVector3i pos) { + public byte getSunlightRegen(Vector3ic pos) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } @@ -268,7 +268,7 @@ public byte getSunlightRegen(int x, int y, int z) { } @Override - public boolean setSunlightRegen(BaseVector3i pos, byte amount) { + public boolean setSunlightRegen(Vector3ic pos, byte amount) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } @@ -278,7 +278,7 @@ public boolean setSunlightRegen(int x, int y, int z, byte amount) { } @Override - public byte getLight(BaseVector3i pos) { + public byte getLight(Vector3ic pos) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } @@ -288,7 +288,7 @@ public byte getLight(int x, int y, int z) { } @Override - public boolean setLight(BaseVector3i pos, byte amount) { + public boolean setLight(Vector3ic pos, byte amount) { throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE); } diff --git a/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java index 852a485e2c2..c9eb8370321 100644 --- a/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/LodChunkProvider.java @@ -228,7 +228,7 @@ public void shutdown() { */ private void tintChunk(Chunk chunk) { for (Vector3ic pos : Chunks.CHUNK_REGION) { - chunk.setSunlight(JomlUtil.from(pos), (byte) (0.75f * chunk.getSunlight(JomlUtil.from(pos)))); + chunk.setSunlight(pos, (byte) (0.75f * chunk.getSunlight(pos))); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java index 84b87b53e99..69f5ef10aa2 100644 --- a/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/world/chunks/internal/ChunkImpl.java @@ -187,7 +187,7 @@ public Block setBlock(Vector3ic pos, Block block) { } @Override - public byte getSunlight(BaseVector3i pos) { + public byte getSunlight(Vector3ic pos) { return getSunlight(pos.x(), pos.y(), pos.z()); } @@ -197,7 +197,7 @@ public byte getSunlight(int x, int y, int z) { } @Override - public boolean setSunlight(BaseVector3i pos, byte amount) { + public boolean setSunlight(Vector3ic pos, byte amount) { return setSunlight(pos.x(), pos.y(), pos.z(), amount); } @@ -208,7 +208,7 @@ public boolean setSunlight(int x, int y, int z, byte amount) { } @Override - public byte getSunlightRegen(BaseVector3i pos) { + public byte getSunlightRegen(Vector3ic pos) { return getSunlightRegen(pos.x(), pos.y(), pos.z()); } @@ -218,7 +218,7 @@ public byte getSunlightRegen(int x, int y, int z) { } @Override - public boolean setSunlightRegen(BaseVector3i pos, byte amount) { + public boolean setSunlightRegen(Vector3ic pos, byte amount) { return setSunlightRegen(pos.x(), pos.y(), pos.z(), amount); } @@ -229,7 +229,7 @@ public boolean setSunlightRegen(int x, int y, int z, byte amount) { } @Override - public byte getLight(BaseVector3i pos) { + public byte getLight(Vector3ic pos) { return getLight(pos.x(), pos.y(), pos.z()); } @@ -239,7 +239,7 @@ public byte getLight(int x, int y, int z) { } @Override - public boolean setLight(BaseVector3i pos, byte amount) { + public boolean setLight(Vector3ic pos, byte amount) { return setLight(pos.x(), pos.y(), pos.z(), amount); } diff --git a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java index 4c98995f2ba..045ce9c52ef 100644 --- a/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/ChunkViewCoreImpl.java @@ -112,7 +112,7 @@ public byte getSunlight(int blockX, int blockY, int blockZ) { if (blockRegion.contains(blockX, blockY, blockZ)) { Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; if (chunk != null) { - return chunk.getSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + return chunk.getSunlight(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())); } } return 0; @@ -123,7 +123,7 @@ public byte getLight(int blockX, int blockY, int blockZ) { if (blockRegion.contains(blockX, blockY, blockZ)) { Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; if (chunk != null) { - return chunk.getLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()))); + return chunk.getLight(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())); } } return 0; @@ -156,7 +156,7 @@ public void setLight(int blockX, int blockY, int blockZ, byte light) { if (blockRegion.contains(blockX, blockY, blockZ)) { Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; if (chunk != null) { - chunk.setLight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); + chunk.setLight(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), light); return; } } @@ -173,7 +173,7 @@ public void setSunlight(int blockX, int blockY, int blockZ, byte light) { if (blockRegion.contains(blockX, blockY, blockZ)) { Chunk chunk = chunks[relChunkIndex(blockX, blockY, blockZ)]; if (chunk != null) { - chunk.setSunlight(JomlUtil.from(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i())), light); + chunk.setSunlight(Chunks.toRelative(blockX, blockY, blockZ, chunkFilterSize, new Vector3i()), light); return; } } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index d3fd7617fd9..c2c254bfd4e 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -288,7 +288,7 @@ public byte getLight(int x, int y, int z) { LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); - return chunk.getLight(JomlUtil.from(blockPos)); + return chunk.getLight(blockPos); } return 0; } @@ -299,7 +299,7 @@ public byte getSunlight(int x, int y, int z) { LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); - return chunk.getSunlight(JomlUtil.from(blockPos)); + return chunk.getSunlight(blockPos); } return 0; } @@ -310,7 +310,7 @@ public byte getTotalLight(int x, int y, int z) { LitChunk chunk = chunkProvider.getChunk(chunkPos); if (chunk != null) { Vector3i blockPos = Chunks.toRelative(x, y, z, new Vector3i()); - return (byte) Math.max(chunk.getSunlight(JomlUtil.from(blockPos)), chunk.getLight(JomlUtil.from(blockPos))); + return (byte) Math.max(chunk.getSunlight(blockPos), chunk.getLight(blockPos)); } return 0; } diff --git a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java index f78d6d2ef07..7e6d5c671c1 100644 --- a/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java +++ b/engine/src/main/java/org/terasology/world/propagation/SunlightRegenBatchPropagator.java @@ -246,8 +246,8 @@ private void propagateSweep(LitChunk fromChunk, LitChunk toChunk, int[] depth, i regenRules.setValue(toChunk, pos, expectedValue); depth[depthIndex]++; byte sunlight = (byte) (expectedValue - Chunks.SUNLIGHT_REGEN_THRESHOLD); - if (sunlight > 0 && sunlight > toChunk.getSunlight(JomlUtil.from(pos))) { - toChunk.setSunlight(JomlUtil.from(pos), sunlight); + if (sunlight > 0 && sunlight > toChunk.getSunlight(pos)) { + toChunk.setSunlight(pos, sunlight); } if (expectedValue < Chunks.MAX_SUNLIGHT_REGEN) { expectedValue++; diff --git a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java index 461b4938c5e..0936a38ea62 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/LightPropagationRules.java @@ -16,7 +16,6 @@ package org.terasology.world.propagation.light; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.world.block.Block; import org.terasology.world.chunks.Chunks; @@ -70,7 +69,7 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { @Override public void setValue(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setLight(JomlUtil.from(pos), value); + chunk.setLight(pos, value); } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java index ffbebc880d5..9dd98e583df 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/LightWorldView.java @@ -16,7 +16,6 @@ package org.terasology.world.propagation.light; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.AbstractFullWorldView; @@ -33,11 +32,11 @@ public LightWorldView(ChunkProvider chunkProvider) { @Override protected byte getValueAt(LitChunk chunk, Vector3ic pos) { - return chunk.getLight(JomlUtil.from(pos)); + return chunk.getLight(pos); } @Override protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setLight(JomlUtil.from(pos), value); + chunk.setLight(pos, value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java index d50541fd8ef..d19a85d01ea 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightPropagationRules.java @@ -16,7 +16,6 @@ package org.terasology.world.propagation.light; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.math.Side; import org.terasology.world.block.Block; import org.terasology.world.chunks.Chunks; @@ -82,7 +81,7 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { @Override public void setValue(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setSunlight(JomlUtil.from(pos), value); + chunk.setSunlight(pos, value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java index a663c2858cf..2b70767f187 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenPropagationRules.java @@ -74,7 +74,7 @@ public byte getValue(LitChunk chunk, int x, int y, int z) { @Override public void setValue(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setSunlightRegen(JomlUtil.from(pos), value); + chunk.setSunlightRegen(pos, value); } /** diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java index 1e346f7a827..f5b82f76cd8 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightRegenWorldView.java @@ -34,11 +34,11 @@ public SunlightRegenWorldView(ChunkProvider chunkProvider) { @Override protected byte getValueAt(LitChunk chunk, Vector3ic pos) { - return chunk.getSunlightRegen(JomlUtil.from(pos)); + return chunk.getSunlightRegen(pos); } @Override protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setSunlightRegen(JomlUtil.from(pos), value); + chunk.setSunlightRegen(pos, value); } } diff --git a/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java b/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java index 72d4dd3a334..aa24bde7c19 100644 --- a/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/light/SunlightWorldView.java @@ -16,7 +16,6 @@ package org.terasology.world.propagation.light; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.LitChunk; import org.terasology.world.propagation.AbstractFullWorldView; @@ -34,12 +33,12 @@ public SunlightWorldView(ChunkProvider chunkProvider) { @Override protected byte getValueAt(LitChunk chunk, Vector3ic pos) { - return chunk.getSunlight(JomlUtil.from(pos)); + return chunk.getSunlight(pos); } @Override protected void setValueAt(LitChunk chunk, Vector3ic pos, byte value) { - chunk.setSunlight(JomlUtil.from(pos), value); + chunk.setSunlight(pos, value); } } From e0add969475dd42d4a0c2a5025a138c291ff05f9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 12:34:19 -0800 Subject: [PATCH 188/259] feat(JOML): remove MatrixUtils (#4448) --- .../java/org/terasology/math/MatrixUtils.java | 346 ------------------ .../rendering/cameras/OrthographicCamera.java | 1 - 2 files changed, 347 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/math/MatrixUtils.java diff --git a/engine/src/main/java/org/terasology/math/MatrixUtils.java b/engine/src/main/java/org/terasology/math/MatrixUtils.java deleted file mode 100644 index de14d8ded9e..00000000000 --- a/engine/src/main/java/org/terasology/math/MatrixUtils.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.terasology.math; - -import org.joml.Matrix3fc; -import org.joml.Matrix4fc; -import org.lwjgl.BufferUtils; -import org.terasology.math.geom.BaseMatrix4f; -import org.terasology.math.geom.Matrix3f; -import org.terasology.math.geom.Matrix4f; -import org.terasology.math.geom.Quat4f; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; - -/** - * Collection of matrix utilities. - * - */ -@Deprecated -public final class MatrixUtils { - - private MatrixUtils() { - } - - /** - * Copies the given matrix into a newly allocated FloatBuffer. - * The order of the elements is column major (as used by OpenGL). - * - * @param m the matrix to copy - * @return A new FloatBuffer containing the matrix in column-major form. - * @deprecated used JOML method that uses {@link Matrix4fc} - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix4f m) { - FloatBuffer buffer = BufferUtils.createFloatBuffer(16); - matrixToFloatBuffer(m, buffer); - return buffer; - } - - /** - * @deprecated used JOML method that uses {@link Matrix4fc} - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix4fc m) { - return m.getTransposed(BufferUtils.createFloatBuffer(16)); - } - - - /** - * Copies the given matrix into a newly allocated FloatBuffer. - * The order of the elements is column major (as used by OpenGL). - * - * @param m the matrix to copy - * @return A new FloatBuffer containing the matrix in column-major form. - * @deprecated used JOML method that uses {@link Matrix3fc} - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix3f m) { - FloatBuffer buffer = BufferUtils.createFloatBuffer(9); - matrixToFloatBuffer(m, buffer); - return buffer; - } - - /** - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link Matrix3fc#get(ByteBuffer)} - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix3fc m) { - return m.getTransposed(BufferUtils.createFloatBuffer(9)); - } - - /** - * Copies the given matrix into an existing FloatBuffer. - * The order of the elements is column major (as used by OpenGL). - * - * @param m the matrix to copy - * @param fb the float buffer to copy the matrix into - * @return The provided float buffer. - * @deprecated This is being replaced with JOML methods - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix3f m, FloatBuffer fb) { - fb.put(m.m00); - fb.put(m.m10); - fb.put(m.m20); - fb.put(m.m01); - fb.put(m.m11); - fb.put(m.m21); - fb.put(m.m02); - fb.put(m.m12); - fb.put(m.m22); - - fb.flip(); - return fb; - } - - /** - * Copies the given matrix into an existing FloatBuffer. - * The order of the elements is column major (as used by OpenGL). - * - * @param m the matrix to copy - * @param fb the float buffer to copy the matrix into - * @return The provided float buffer. - * @deprecated This is being replaced with JOML methods - */ - @Deprecated - public static FloatBuffer matrixToFloatBuffer(Matrix4f m, FloatBuffer fb) { - fb.put(m.m00); - fb.put(m.m10); - fb.put(m.m20); - fb.put(m.m30); - fb.put(m.m01); - fb.put(m.m11); - fb.put(m.m21); - fb.put(m.m31); - fb.put(m.m02); - fb.put(m.m12); - fb.put(m.m22); - fb.put(m.m32); - fb.put(m.m03); - fb.put(m.m13); - fb.put(m.m23); - fb.put(m.m33); - - fb.flip(); - return fb; - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link org.joml.Matrix4f#setLookAt(float, float, float, float, float, float, float, float, float)}. - */ - @Deprecated - public static org.joml.Matrix4f createViewMatrix(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { - return createViewMatrix(new org.joml.Vector3f(eyeX, eyeY, eyeZ), new org.joml.Vector3f(centerX, centerY, centerZ), new org.joml.Vector3f(upX, upY, upZ)); - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link org.joml.Matrix4f#setLookAt(float, float, float, float, float, float, float, float, float)}. - */ - @Deprecated - public static org.joml.Matrix4f createViewMatrix(org.joml.Vector3f eye, org.joml.Vector3f center, org.joml.Vector3f up) { - org.joml.Matrix4f m = new org.joml.Matrix4f(); - - org.joml.Vector3f f = new org.joml.Vector3f(); - center.sub(eye,f); - - f.normalize(); - up.normalize(); - - org.joml.Vector3f s = new org.joml.Vector3f(); - f.cross(up,s); - s.normalize(); - - org.joml.Vector3f u = new org.joml.Vector3f(); - s.cross(f,u); - u.normalize(); - - m.m00(s.x); - m.m10(s.y); - m.m20(s.z); - m.m30(0); - m.m01(u.x); - m.m11(u.y); - m.m21(u.z); - m.m31(0); - m.m02(-f.x); - m.m12(-f.y); - m.m22(-f.z); - m.m32(0); - m.m03(0); - m.m13(0); - m.m23(0); - m.m33(1); - - m.m30(-eye.x); - m.m31(-eye.y); - m.m32(-eye.z); - - m.transpose(); - - return m; - } - - - /** - * - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link org.joml.Matrix4f#setOrtho(float, float, float, float, float, float)}. - */ - @Deprecated - public static org.joml.Matrix4f createOrthogonalProjectionMatrix(float left, float right, float top, float bottom, float near, float far) { - org.joml.Matrix4f m = new org.joml.Matrix4f(); - - float lateral = right - left; - float vertical = top - bottom; - float forward = far - near; - float tx = -(right + left) / (right - left); - float ty = -(top + bottom) / (top - bottom); - float tz = -(far + near) / (far - near); - - m.m00(2.0f / lateral); - m.m10(0.0f); - m.m20(0.0f); - m.m30(tx); - m.m01(0.0f); - m.m11(2.0f / vertical); - m.m21(0.0f); - m.m31(ty); - m.m02(0.0f); - m.m12(0.0f); - m.m22(-2.0f / forward); - m.m32(tz); - m.m03(0.0f); - m.m13(0.0f); - m.m23(0.0f); - m.m33(1.0f); - - m.transpose(); - - return m; - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link org.joml.Matrix4f#setPerspective(float, float, float, float)}. - */ - @Deprecated - public static org.joml.Matrix4f createPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar) { - org.joml.Matrix4f m = new org.joml.Matrix4f(); - - float f = 1.0f / (float) Math.tan((double) fovY * 0.5f); - - m.m00(f / aspectRatio); - m.m10(0); - m.m20(0); - m.m30(0); - m.m01(0); - m.m11(f); - m.m21(0); - m.m31(0); - m.m02(0); - m.m12(0); - m.m22((zFar + zNear) / (zNear - zFar)); - m.m32((2 * zFar * zNear) / (zNear - zFar)); - m.m03(0); - m.m13(0); - m.m23(-1); - m.m33(0); - - m.transpose(); - - return m; - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version use JOML multiplication. - */ - @Deprecated - public static org.joml.Matrix4f calcViewProjectionMatrix(org.joml.Matrix4f vm, org.joml.Matrix4f p) { - return new org.joml.Matrix4f(p).mul(vm); - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version use JOML multiplication. - */ - @Deprecated - public static Matrix4f calcModelViewMatrix(Matrix4f m, Matrix4f vm) { - Matrix4f result = new Matrix4f(); - result.mul(m, vm); - return result; - } - - /** - * - * @deprecated This is scheduled for removal in an upcoming version use JOML multiplication. - */ - @Deprecated - public static Matrix4f calcModelViewMatrix(Matrix4fc m, Matrix4f vm) { - Matrix4f result = new Matrix4f(JomlUtil.from(m)); - result.transpose(); - result.mul(vm); - return result; - } - - /** - * @return This is scheduled for removal in an upcoming version use JOML get3x3 invert and transpose. - * @deprecated This is scheduled for removal in an upcoming version use JOML methods. - */ - @Deprecated - public static Matrix3f calcNormalMatrix(Matrix4f mv) { - Matrix3f result = new Matrix3f(); - result.m00 = mv.m00; - result.m10 = mv.m10; - result.m20 = mv.m20; - result.m01 = mv.m01; - result.m11 = mv.m11; - result.m21 = mv.m21; - result.m02 = mv.m02; - result.m12 = mv.m12; - result.m22 = mv.m22; - - result.invert(); - result.transpose(); - return result; - } - - /** - * This method pulls out the rotation component of a transformation matrix - that is a matrix - * which is the composition of a translation, rotation and scale. It will produce odd results - * on other matrices. - * It works by determining and removing the scale element (which is represented along the diagonal - * of the matrix - the rotation part of the matrix remains on upper left 3x3 portion of the matrix - * (translation is on the fourth column). See - *
    Rotation matrix - * @param m The transformation matrix to extract rotation from - * @return The rotation component of a transformation matrix - */ - public static Quat4f extractRotation(BaseMatrix4f m) { - float w = (float) (Math.sqrt(1 + m.getM00() + m.getM11() + m.getM22()) / 2.0f); - float denom = 4 * w; - return new Quat4f((m.getM21() - m.getM12()) / denom, (m.getM02() - m.getM20()) / denom, (m.getM10() - m.getM01()) / denom, w); - } -} diff --git a/engine/src/main/java/org/terasology/rendering/cameras/OrthographicCamera.java b/engine/src/main/java/org/terasology/rendering/cameras/OrthographicCamera.java index f0e4bbb35a8..51c87c25b51 100644 --- a/engine/src/main/java/org/terasology/rendering/cameras/OrthographicCamera.java +++ b/engine/src/main/java/org/terasology/rendering/cameras/OrthographicCamera.java @@ -17,7 +17,6 @@ import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; -import org.terasology.math.MatrixUtils; import static org.lwjgl.opengl.GL11.GL_PROJECTION; import static org.lwjgl.opengl.GL11.glMatrixMode; From 512e8cfe201c98a494ea965a542024b2ccf307d2 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 2 Feb 2021 13:09:10 -0800 Subject: [PATCH 189/259] build(PC): get access to kotlin.test as api dependency instead of explicit delegation --- buildSrc/build.gradle.kts | 2 +- .../src/main/kotlin/terasology-dist.gradle.kts | 17 ++--------------- facades/PC/build.gradle.kts | 2 ++ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b42130d4cba..ee95c03e5b2 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -26,5 +26,5 @@ dependencies { // for inspecting modules implementation("org.terasology:gestalt-module:5.1.5") - implementation(kotlin("test")) + api(kotlin("test")) } diff --git a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts index b06ba3cf58a..e89274f4026 100644 --- a/buildSrc/src/main/kotlin/terasology-dist.gradle.kts +++ b/buildSrc/src/main/kotlin/terasology-dist.gradle.kts @@ -1,6 +1,8 @@ // Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +import kotlin.test.assertEquals + /** * Make assertions about the content of a zip file. * @@ -46,19 +48,6 @@ open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : zipFile.set(taskProvider.flatMap { it.archiveFile }) } - /** - * Assert two objects are equal. - * - * @see kotlin.test.assertEquals - */ - fun assertEquals(expected: Any, actual: Any, message: String? = null) = - kotlin.test.assertEquals(expected, actual, message) - - /** - * Fail this test with the given message. - */ - fun fail(message: String): Nothing = kotlin.test.fail(message) - /** * Assert the zip contains exactly one match for the given pattern. * @@ -70,5 +59,3 @@ open class ValidateZipDistribution @Inject constructor(objects: ObjectFactory) : }.count(), "Matches for $pattern") } } - - diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index 0bc1b729c14..dd8bd721c28 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -8,6 +8,8 @@ import org.apache.tools.ant.filters.FixCrLfFilter import org.apache.tools.ant.taskdefs.condition.Os import java.text.SimpleDateFormat import java.util.* +import kotlin.test.assertEquals +import kotlin.test.fail plugins { application From c3db91e750543129c55c8939dc28d8b6fc5e1e59 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Tue, 2 Feb 2021 22:35:10 +0100 Subject: [PATCH 190/259] fix: add `org.terasology.joml` to API whitelist (#4455) Fixes #4453 --- .../java/org/terasology/engine/module/ExternalApiWhitelist.java | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/main/java/org/terasology/engine/module/ExternalApiWhitelist.java b/engine/src/main/java/org/terasology/engine/module/ExternalApiWhitelist.java index 2c8b6b0eb23..72933f79543 100644 --- a/engine/src/main/java/org/terasology/engine/module/ExternalApiWhitelist.java +++ b/engine/src/main/java/org/terasology/engine/module/ExternalApiWhitelist.java @@ -27,6 +27,7 @@ public final class ExternalApiWhitelist { public static final Set PACKAGES = new ImmutableSet.Builder() // TODO: This one org.terasology entry is a hack and needs a proper fix .add("org.terasology.math.geom") + .add("org.terasology.joml.geom") .add("java.lang") .add("java.beans") .add("java.lang.invoke") From 6ace17598461d2eb0d30bf8647b5b4d2546be303 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Feb 2021 13:37:17 -0800 Subject: [PATCH 191/259] feat(JOML): migrate RotationTest (#4457) --- .../org/terasology/math/RotationTest.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/math/RotationTest.java b/engine-tests/src/test/java/org/terasology/math/RotationTest.java index 21bbf7f1ce6..37fa27cc1dd 100644 --- a/engine-tests/src/test/java/org/terasology/math/RotationTest.java +++ b/engine-tests/src/test/java/org/terasology/math/RotationTest.java @@ -17,9 +17,9 @@ import com.google.common.collect.Iterables; import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector3f; import org.junit.jupiter.api.Test; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.terasology.joml.test.QuaternionAssert.assertEquals; @@ -36,8 +36,8 @@ public void testRotateSideNone() { @Test public void testRotateSideYaw() { Rotation rotation = Rotation.rotate(Yaw.CLOCKWISE_90); - Quat4f rot = rotation.getQuat4f(); - Vector3f dir = rot.rotate(Side.FRONT.toDirection().getVector3f(), new Vector3f()); + Quaternionfc rot = rotation.orientation(); + Vector3f dir = rot.transform(Side.FRONT.toDirection().asVector3f(), new Vector3f()); assertEquals(Direction.inDirection(dir).toSide(), rotation.rotate(Side.FRONT)); assertEquals(Side.LEFT, Rotation.rotate(Yaw.CLOCKWISE_90).rotate(Side.FRONT)); @@ -46,21 +46,21 @@ public void testRotateSideYaw() { @Test public void testOrientation() { - assertEquals(new Quaternionf().rotationYXZ(90.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_90).orientation(),0.001f); - assertEquals(new Quaternionf().rotationYXZ(180.0f * TeraMath.DEG_TO_RAD,0,0), Rotation.rotate(Yaw.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(90.0f * TeraMath.DEG_TO_RAD, 0, 0), Rotation.rotate(Yaw.CLOCKWISE_90).orientation(), 0.001f); + assertEquals(new Quaternionf().rotationYXZ(180.0f * TeraMath.DEG_TO_RAD, 0, 0), Rotation.rotate(Yaw.CLOCKWISE_180).orientation(), 0.001f); - assertEquals(new Quaternionf().rotationYXZ(0,90.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_90).orientation(),0.001f); - assertEquals(new Quaternionf().rotationYXZ(0,180.0f * TeraMath.DEG_TO_RAD,0), Rotation.rotate(Pitch.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0, 90.0f * TeraMath.DEG_TO_RAD, 0), Rotation.rotate(Pitch.CLOCKWISE_90).orientation(), 0.001f); + assertEquals(new Quaternionf().rotationYXZ(0, 180.0f * TeraMath.DEG_TO_RAD, 0), Rotation.rotate(Pitch.CLOCKWISE_180).orientation(), 0.001f); - assertEquals(new Quaternionf().rotationYXZ(0,0,90.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_90).orientation(),0.001f); - assertEquals(new Quaternionf().rotationYXZ(0,0,180.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_180).orientation(),0.001f); + assertEquals(new Quaternionf().rotationYXZ(0, 0, 90.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_90).orientation(), 0.001f); + assertEquals(new Quaternionf().rotationYXZ(0, 0, 180.0f * TeraMath.DEG_TO_RAD), Rotation.rotate(Roll.CLOCKWISE_180).orientation(), 0.001f); } @Test public void testRotateSidePitch() { Rotation rotation = Rotation.rotate(Pitch.CLOCKWISE_90); - Quat4f rot = rotation.getQuat4f(); - Vector3f dir = rot.rotate(Side.FRONT.toDirection().getVector3f(), new Vector3f()); + Quaternionfc rot = rotation.orientation(); + Vector3f dir = rot.transform(Side.FRONT.toDirection().asVector3f(), new Vector3f()); assertEquals(Direction.inDirection(dir).toSide(), rotation.rotate(Side.FRONT)); assertEquals(Side.TOP, Rotation.rotate(Pitch.CLOCKWISE_90).rotate(Side.FRONT)); @@ -70,8 +70,8 @@ public void testRotateSidePitch() { @Test public void testRotateSideRoll() { Rotation rotation = Rotation.rotate(Roll.CLOCKWISE_90); - Quat4f rot = rotation.getQuat4f(); - Vector3f dir = rot.rotate(Side.TOP.toDirection().getVector3f(), new Vector3f()); + Quaternionfc rot = rotation.orientation(); + Vector3f dir = rot.transform(Side.TOP.toDirection().asVector3f(), new Vector3f()); assertEquals(Direction.inDirection(dir).toSide(), rotation.rotate(Side.TOP)); assertEquals(Side.LEFT, Rotation.rotate(Roll.CLOCKWISE_90).rotate(Side.TOP)); @@ -81,8 +81,8 @@ public void testRotateSideRoll() { @Test public void testRotateMixed() { Rotation rotation = Rotation.rotate(Yaw.CLOCKWISE_180, Pitch.CLOCKWISE_90, Roll.CLOCKWISE_90); - Quat4f rot = rotation.getQuat4f(); - Vector3f dir = rot.rotate(Side.FRONT.toDirection().getVector3f(), new Vector3f()); + Quaternionfc rot = rotation.orientation(); + Vector3f dir = rot.transform(Side.FRONT.toDirection().asVector3f(), new Vector3f()); assertEquals(Direction.inDirection(dir).toSide(), rotation.rotate(Side.FRONT)); } From 976b0ac976cdd48d6cef9b3624bcf13023b7df70 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 11:17:39 -0800 Subject: [PATCH 192/259] CI: include testDist task --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index b6b7d5b6828..2bf562fcb24 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -23,7 +23,7 @@ node ("heavy-java") { } stage('Build') { // Jenkins sometimes doesn't run Gradle automatically in plain console mode, so make it explicit - sh './gradlew --console=plain clean extractConfig extractNatives distForLauncher' + sh './gradlew --console=plain clean extractConfig extractNatives distForLauncher testDist' archiveArtifacts 'gradlew, gradle/wrapper/*, templates/build.gradle, config/**, facades/PC/build/distributions/Terasology.zip, build/resources/main/org/terasology/version/versionInfo.properties, natives/**, buildSrc/src/**, buildSrc/*.kts' } stage('Publish') { From 6e51e06713cc69b23b6c08992bd25fbdd0446f2c Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 11:32:08 -0800 Subject: [PATCH 193/259] build(PC): GIT_BRANCH is no longer used for build information --- facades/PC/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/facades/PC/build.gradle.kts b/facades/PC/build.gradle.kts index dd8bd721c28..362592b5932 100644 --- a/facades/PC/build.gradle.kts +++ b/facades/PC/build.gradle.kts @@ -218,7 +218,8 @@ tasks.named("jar") { // "line is too long" errors: https://github.com/gradle/gradle/issues/1989 attributes["Class-Path"] = configurations["runtimeClasspath"].joinToString(" ") { it.name } attributes["Implementation-Title"] = "Terasology-" + project.name - attributes["Implementation-Version"] = """${env["BUILD_NUMBER"]}, ${env["GIT_BRANCH"]}, ${env["BUILD_ID"]}""" + attributes["Implementation-Version"] = + "$displayVersion, facade v${project.version}, build number ${env["BUILD_NUMBER"]}" } } From f742dd06f2f5564c0b934d9d1b70b845e5604409 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 15:29:15 -0800 Subject: [PATCH 194/259] build(common): refactor repositories to plugin `terasology-repositories` --- .../kotlin/terasology-repositories.gradle.kts | 36 +++++++++++++++++++ config/gradle/common.gradle | 36 ++----------------- 2 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 buildSrc/src/main/kotlin/terasology-repositories.gradle.kts diff --git a/buildSrc/src/main/kotlin/terasology-repositories.gradle.kts b/buildSrc/src/main/kotlin/terasology-repositories.gradle.kts new file mode 100644 index 00000000000..8161abeaf0e --- /dev/null +++ b/buildSrc/src/main/kotlin/terasology-repositories.gradle.kts @@ -0,0 +1,36 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +import java.net.URI + +// We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on +repositories { + // External libs - jcenter is Bintray and a superset of Maven Central + jcenter { + content { + // This is first choice for most java dependencies, but assume we'll need to check our + // own repository for things from our own organization. + // (This is an optimization so gradle doesn't try to find our hundreds of modules + // in jcenter.) + excludeGroupByRegex("""org\.terasology(\..+)?""") + } + } + + // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs + maven { + val repoViaEnv = System.getenv()["RESOLUTION_REPO"] + if (rootProject.hasProperty("alternativeResolutionRepo")) { + // If the user supplies an alternative repo via gradle.properties then use that + name = "from alternativeResolutionRepo property" + url = URI(rootProject.properties["alternativeResolutionRepo"] as String) + } else if (repoViaEnv != null && repoViaEnv != "") { + name = "from \$RESOLUTION_REPO" + url = URI(repoViaEnv) + } else { + // Our default is the main virtual repo containing everything except repos for testing Artifactory itself + name = "Terasology Artifactory" + url = URI("http://artifactory.terasology.org/artifactory/virtual-repo-live") + isAllowInsecureProtocol = true // 😱 + } + } +} diff --git a/config/gradle/common.gradle b/config/gradle/common.gradle index ba4c7d344b6..206eaa6685a 100644 --- a/config/gradle/common.gradle +++ b/config/gradle/common.gradle @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 // language @@ -16,6 +16,8 @@ apply plugin: 'com.github.spotbugs' apply plugin: 'jacoco' apply plugin: 'org.sonarqube' +apply plugin: 'terasology-repositories' + sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -25,38 +27,6 @@ tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } -// We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on -repositories { - // External libs - jcenter is Bintray and a superset of Maven Central - jcenter { - content { - // This is first choice for most java dependencies, but assume we'll need to check our - // own repository for things from our own organization. - // (This is an optimization so gradle doesn't try to find our hundreds of modules - // in jcenter.) - excludeGroupByRegex(/org\.terasology(\..+)?/) - } - } - - // MovingBlocks Artifactory instance for libs not readily available elsewhere plus our own libs - maven { - def repoViaEnv = System.getenv()["RESOLUTION_REPO"] - if (rootProject.hasProperty("alternativeResolutionRepo")) { - // If the user supplies an alternative repo via gradle.properties then use that - name "from alternativeResolutionRepo property" - url alternativeResolutionRepo - } else if (repoViaEnv != null && repoViaEnv != "") { - name "from \$RESOLUTION_REPO" - url = repoViaEnv - } else { - // Our default is the main virtual repo containing everything except repos for testing Artifactory itself - name "Terasology Artifactory" - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" - allowInsecureProtocol true // 😱 - } - } -} - dependencies { pmd('net.sourceforge.pmd:pmd-core:6.15.0') pmd('net.sourceforge.pmd:pmd-java:6.15.0') From e0b16660e99d2d99bab38de35f6d1bef48a1ed45 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 15:58:44 -0800 Subject: [PATCH 195/259] build(PC): cacheModules is an output of :modules rather than facade being responsible for knowing too many things about modules. --- .gitignore | 2 +- buildSrc/src/main/kotlin/facade.gradle.kts | 31 ++++++---------- .../org/terasology/gradology/attributes.kt | 11 ++++++ .../kotlin/org/terasology/gradology/exec.kt | 4 +- .../terasology/engine/paths/PathManager.java | 2 +- modules/build.gradle.kts | 37 ++++++++++++++++++- 6 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt diff --git a/.gitignore b/.gitignore index b6d624113e9..c8926248364 100644 --- a/.gitignore +++ b/.gitignore @@ -72,7 +72,7 @@ Thumbs.db /configs/ /screenshots/ /logs/ -/moduleCache/ +/cacheModules/ /terasology-server/ /terasology-2ndclient/ /terasology-3rdclient/ diff --git a/buildSrc/src/main/kotlin/facade.gradle.kts b/buildSrc/src/main/kotlin/facade.gradle.kts index 2e0e1ca8867..e5014974c4c 100644 --- a/buildSrc/src/main/kotlin/facade.gradle.kts +++ b/buildSrc/src/main/kotlin/facade.gradle.kts @@ -1,7 +1,8 @@ // Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 -import org.terasology.gradology.moduleDependencyArtifacts +import org.terasology.gradology.JAR_COLLECTION +import org.terasology.gradology.namedAttribute plugins { application @@ -13,33 +14,23 @@ configurations { register("natives") { description = "native libraries (.dll and .so)" } - val modulesConfig = register("modules") { - description = "locally built modules and their dependencies" + register("modules") { + description = "dependencies of locally built modules" - resolutionStrategy { - preferProjectModules() + attributes { + // Specifying we need JAR_COLLECTION is how we indicate a dependency on cacheModules. + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, namedAttribute(JAR_COLLECTION)) } } - named("compileOnly") { - // Include modules in compileOnly so IntelliJ thinks to compile them. - extendsFrom(modulesConfig.get()) - } } dependencies { "natives"(files(rootProject.file(dirNatives)).builtBy(":extractNatives")) - // Make sure any local module builds are up-to-date and have their dependencies by declaring - // a runtime dependency on whatever the `:modules` subproject declares. - // This won't add anything if there are no modules checked out. - "modules"(platform(project(":modules"))) -} - -tasks.register("provideModuleDependencies") { - destinationDir = rootProject.file("moduleCache") + // Include modules in compileOnly so IntelliJ thinks to compile them. + compileOnly(platform(project(":modules"))) - val modulesConfig = configurations.named("modules") - val artifactsProvider = moduleDependencyArtifacts(modulesConfig) - from(artifactsProvider.map { artifacts -> artifacts.map(ResolvedArtifactResult::getFile) }) + // Make sure all module dependencies are available to the game in cacheModules. + "modules"(project(":modules")) } diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt new file mode 100644 index 00000000000..a2effd1995c --- /dev/null +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt @@ -0,0 +1,11 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.gradology + +import org.gradle.api.Named +import org.gradle.api.Project + +inline fun Project.namedAttribute(value: String) = objects.named(T::class.java, value) + +const val JAR_COLLECTION = "jar-collection" diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index 0ca51e58747..dfa64e70afa 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -52,9 +52,9 @@ open class RunTerasology : JavaExec() { } private fun initConfig() { - dependsOn(project.configurations["natives"]) + dependsOn(project.configurations.named("natives")) classpath(project.the()["main"].runtimeClasspath) - dependsOn("provideModuleDependencies") + dependsOn(project.configurations.named("modules")) args("-homedir") jvmArgs("-Xmx3072m") diff --git a/engine/src/main/java/org/terasology/engine/paths/PathManager.java b/engine/src/main/java/org/terasology/engine/paths/PathManager.java index 27d3f39861f..b2d9d471e16 100644 --- a/engine/src/main/java/org/terasology/engine/paths/PathManager.java +++ b/engine/src/main/java/org/terasology/engine/paths/PathManager.java @@ -33,7 +33,7 @@ public final class PathManager { private static final String LOG_DIR = "logs"; private static final String SHADER_LOG_DIR = "shaders"; private static final String MOD_DIR = "modules"; - private static final String MOD_CACHE_DIR = "moduleCache"; + private static final String MOD_CACHE_DIR = "cacheModules"; private static final String SCREENSHOT_DIR = "screenshots"; private static final String NATIVES_DIR = "natives"; private static final String CONFIGS_DIR = "configs"; diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts index d51022963af..000209e03ec 100644 --- a/modules/build.gradle.kts +++ b/modules/build.gradle.kts @@ -1,10 +1,18 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2021 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 +import org.terasology.gradology.JAR_COLLECTION +import org.terasology.gradology.moduleDependencyArtifacts +import org.terasology.gradology.namedAttribute + plugins { + `terasology-repositories` `java-platform` } +@Suppress("PropertyName") +val CACHE_MODULES_DIR = rootProject.file("cacheModules") + javaPlatform { allowDependencies() } @@ -16,6 +24,33 @@ dependencies { } } +val jarCollection: Configuration by configurations.creating { + description = "Provides cacheModules with JAR_COLLECTION." + + isCanBeConsumed = true + isCanBeResolved = false + + attributes { + attribute(Usage.USAGE_ATTRIBUTE, namedAttribute(Usage.JAVA_RUNTIME)) + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, namedAttribute(JAR_COLLECTION)) + } +} + +val provideModuleDependencies by tasks.registering(Sync::class) { + destinationDir = CACHE_MODULES_DIR + + val artifactsProvider = moduleDependencyArtifacts(configurations.named("classpath")) + from(artifactsProvider.map { artifacts -> artifacts.map(ResolvedArtifactResult::getFile) }) +} + +artifacts { + // The output of our jarCollection configuration comes from this task. + add(jarCollection.name, provideModuleDependencies) { + type = "jar-collection" + } +} + + // Allows using :modules:clean as a shortcut for running clean in each module. tasks.named("clean").configure { val cleanPlatform = this From ebdb5e530a63bc513be59c140101b65c76bb39c2 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 16:00:22 -0800 Subject: [PATCH 196/259] refactor(PathManager): rename MOD_DIR to MODULE_DIR --- .../java/org/terasology/engine/paths/PathManager.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/paths/PathManager.java b/engine/src/main/java/org/terasology/engine/paths/PathManager.java index b2d9d471e16..3e68a2e7060 100644 --- a/engine/src/main/java/org/terasology/engine/paths/PathManager.java +++ b/engine/src/main/java/org/terasology/engine/paths/PathManager.java @@ -32,8 +32,8 @@ public final class PathManager { private static final String RECORDINGS_LIBRARY_DIR = "recordings"; private static final String LOG_DIR = "logs"; private static final String SHADER_LOG_DIR = "shaders"; - private static final String MOD_DIR = "modules"; - private static final String MOD_CACHE_DIR = "cacheModules"; + private static final String MODULE_DIR = "modules"; + private static final String MODULE_CACHE_DIR = "cacheModules"; private static final String SCREENSHOT_DIR = "screenshots"; private static final String NATIVES_DIR = "natives"; private static final String CONFIGS_DIR = "configs"; @@ -302,14 +302,14 @@ private void updateDirs() throws IOException { Files.createDirectories(logPath); shaderLogPath = logPath.resolve(SHADER_LOG_DIR); Files.createDirectories(shaderLogPath); - Path homeModPath = homePath.resolve(MOD_DIR); + Path homeModPath = homePath.resolve(MODULE_DIR); Files.createDirectories(homeModPath); - Path modCachePath = homePath.resolve(MOD_CACHE_DIR); + Path modCachePath = homePath.resolve(MODULE_CACHE_DIR); Files.createDirectories(modCachePath); if (Files.isSameFile(homePath, installPath)) { modPaths = ImmutableList.of(modCachePath, homeModPath); } else { - Path installModPath = installPath.resolve(MOD_DIR); + Path installModPath = installPath.resolve(MODULE_DIR); Files.createDirectories(installModPath); modPaths = ImmutableList.of(installModPath, modCachePath, homeModPath); } From e48cbe83fa0a51ba582ef3fc9d56c209e8a8a888 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Wed, 3 Feb 2021 23:08:58 -0800 Subject: [PATCH 197/259] chore[IntelliJ]: exclude compiler.xml from version control (#4460) Its values are obtained from the gradle configuration. See https://youtrack.jetbrains.com/issue/IDEA-251986 cherry-picked from c1d63f5914c8bf3425db924961ceec7f6e49db12 Co-authored-by: Nail Khanipov --- .idea/.gitignore | 3 +++ .idea/compiler.xml | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 .idea/compiler.xml diff --git a/.idea/.gitignore b/.idea/.gitignore index 6f1ee0cc2b2..e1baec5fbf2 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -22,6 +22,9 @@ workspace.xml /gradle.xml /libraries +# see https://youtrack.jetbrains.com/issue/IDEA-251986 +/compiler.xml + # too much churn with teresology-modules each having their own repo /vcs.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 3058433f8e4..00000000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From 593b32990cc4467766add25ac5a64c7a97956ca6 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:02:38 -0800 Subject: [PATCH 198/259] build(modules): modules are `api` dependency so IntelliJ does them at compile time invoke fetchModuleDependencies in run configs --- .idea/runConfigurations/TerasologyPC.xml | 1 + .../TerasologyPC_for_mac.xml | 1 + modules/build.gradle.kts | 21 +++++++++++++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.idea/runConfigurations/TerasologyPC.xml b/.idea/runConfigurations/TerasologyPC.xml index f40ecf61215..a05616b0da1 100644 --- a/.idea/runConfigurations/TerasologyPC.xml +++ b/.idea/runConfigurations/TerasologyPC.xml @@ -21,6 +21,7 @@
    \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC_for_mac.xml b/.idea/runConfigurations/TerasologyPC_for_mac.xml index cdd019f71d0..14f98d671a4 100644 --- a/.idea/runConfigurations/TerasologyPC_for_mac.xml +++ b/.idea/runConfigurations/TerasologyPC_for_mac.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts index 000209e03ec..4bcde7c5529 100644 --- a/modules/build.gradle.kts +++ b/modules/build.gradle.kts @@ -20,7 +20,7 @@ javaPlatform { dependencies { // This platform depends on each of its subprojects. subprojects { - runtime(this) + api(this) } } @@ -36,25 +36,34 @@ val jarCollection: Configuration by configurations.creating { } } -val provideModuleDependencies by tasks.registering(Sync::class) { +val fetchModuleDependencies by tasks.registering(Sync::class) { + group = "build" + destinationDir = CACHE_MODULES_DIR val artifactsProvider = moduleDependencyArtifacts(configurations.named("classpath")) from(artifactsProvider.map { artifacts -> artifacts.map(ResolvedArtifactResult::getFile) }) } +val cleanFetchModuleDependencies by tasks.registering(Delete::class) { + delete(CACHE_MODULES_DIR) +} + + artifacts { // The output of our jarCollection configuration comes from this task. - add(jarCollection.name, provideModuleDependencies) { + add(jarCollection.name, fetchModuleDependencies) { type = "jar-collection" } } -// Allows using :modules:clean as a shortcut for running clean in each module. tasks.named("clean").configure { - val cleanPlatform = this + dependsOn(cleanFetchModuleDependencies) + + // Allows using :modules:clean as a shortcut for running clean in each module. + val cleanModules = this subprojects { - cleanPlatform.dependsOn(this.tasks.named("clean")) + cleanModules.dependsOn(this.tasks.named("clean")) } } From 1c2376836606d61d30fc12269a2007413a24d6cb Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:14:10 -0800 Subject: [PATCH 199/259] build(modules): link to doc for namedAttribute() --- .../src/main/kotlin/org/terasology/gradology/attributes.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt index a2effd1995c..b1ce73c876f 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/attributes.kt @@ -6,6 +6,11 @@ package org.terasology.gradology import org.gradle.api.Named import org.gradle.api.Project +/** + * Get the attribute value with the given name. + * + * As seen in [Sharing Output Between Projects](https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing). + */ inline fun Project.namedAttribute(value: String) = objects.named(T::class.java, value) const val JAR_COLLECTION = "jar-collection" From 78253eae6e4cce8677fbe9a6db0dafa4abca70c6 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:15:51 -0800 Subject: [PATCH 200/259] build(modules): name the output `cachedModules` A noun phrase is better than a verb for a directory name. --- .gitignore | 2 +- .../src/main/java/org/terasology/engine/paths/PathManager.java | 2 +- modules/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c8926248364..bc38282720a 100644 --- a/.gitignore +++ b/.gitignore @@ -72,7 +72,7 @@ Thumbs.db /configs/ /screenshots/ /logs/ -/cacheModules/ +/cachedModules/ /terasology-server/ /terasology-2ndclient/ /terasology-3rdclient/ diff --git a/engine/src/main/java/org/terasology/engine/paths/PathManager.java b/engine/src/main/java/org/terasology/engine/paths/PathManager.java index 3e68a2e7060..1a0d44ff58e 100644 --- a/engine/src/main/java/org/terasology/engine/paths/PathManager.java +++ b/engine/src/main/java/org/terasology/engine/paths/PathManager.java @@ -33,7 +33,7 @@ public final class PathManager { private static final String LOG_DIR = "logs"; private static final String SHADER_LOG_DIR = "shaders"; private static final String MODULE_DIR = "modules"; - private static final String MODULE_CACHE_DIR = "cacheModules"; + private static final String MODULE_CACHE_DIR = "cachedModules"; private static final String SCREENSHOT_DIR = "screenshots"; private static final String NATIVES_DIR = "natives"; private static final String CONFIGS_DIR = "configs"; diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts index 4bcde7c5529..1a070f341a7 100644 --- a/modules/build.gradle.kts +++ b/modules/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } @Suppress("PropertyName") -val CACHE_MODULES_DIR = rootProject.file("cacheModules") +val CACHE_MODULES_DIR = rootProject.file("cachedModules") javaPlatform { allowDependencies() From 782c88d53b4c929b4f01105986f6b5c6007d12e5 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:56:01 -0800 Subject: [PATCH 201/259] build(IntelliJ): do not add final newline to XML files in .idea IntelliJ's XML serializer doesn't add them, and we don't want to add formatting that gets stripped out again the next time IntelliJ writes out a config file. --- .idea/.editorconfig | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/.editorconfig diff --git a/.idea/.editorconfig b/.idea/.editorconfig new file mode 100644 index 00000000000..f6a6895a91c --- /dev/null +++ b/.idea/.editorconfig @@ -0,0 +1,6 @@ +[*] +charset = utf-8 + +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdd,*.wsdl,*.xjb,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] +# The XML serializer doesn't write final newline, so don't add it during manual edits. +insert_final_newline = false From fe5c83d7119e1178cdd7114ae7ca2610b388a7de Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 4 Feb 2021 11:57:18 -0800 Subject: [PATCH 202/259] build(PC): add fetchModuleDependencies to all Run Configs --- .idea/runConfigurations/TeraEd__rendering_editor_.xml | 1 + .idea/runConfigurations/TerasologyPC__2nd_client_.xml | 1 + .idea/runConfigurations/TerasologyPC__2nd_client_for_mac.xml | 1 + .idea/runConfigurations/TerasologyPC__3rd_client_.xml | 1 + .idea/runConfigurations/TerasologyPC__CR_enabled_.xml | 1 + .idea/runConfigurations/TerasologyPC__EXTREME_8GB_.xml | 1 + .idea/runConfigurations/TerasologyPC__Headless_.xml | 1 + .idea/runConfigurations/TerasologyPC__Java_FlightRecorder_.xml | 1 + .idea/runConfigurations/TerasologyPC__Splash_disabled_.xml | 1 + .idea/runConfigurations/TerasologyPC__load_latest_.xml | 1 + .idea/runConfigurations/TerasologyPC__no_audio_.xml | 1 + .idea/runConfigurations/TerasologyPC__no_saves_.xml | 1 + .idea/runConfigurations/TerasologyPC__permissive_security_.xml | 1 + .idea/runConfigurations/TerasologyPC__recreate_latest_.xml | 1 + .idea/runConfigurations/engine_tests_with_JaCoCo.xml | 1 + 15 files changed, 15 insertions(+) diff --git a/.idea/runConfigurations/TeraEd__rendering_editor_.xml b/.idea/runConfigurations/TeraEd__rendering_editor_.xml index 3c06ba14d61..6006938c49b 100644 --- a/.idea/runConfigurations/TeraEd__rendering_editor_.xml +++ b/.idea/runConfigurations/TeraEd__rendering_editor_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__2nd_client_.xml b/.idea/runConfigurations/TerasologyPC__2nd_client_.xml index 051131ff0f5..9f7f7628e20 100644 --- a/.idea/runConfigurations/TerasologyPC__2nd_client_.xml +++ b/.idea/runConfigurations/TerasologyPC__2nd_client_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__2nd_client_for_mac.xml b/.idea/runConfigurations/TerasologyPC__2nd_client_for_mac.xml index 3749277e448..265d9944dc0 100644 --- a/.idea/runConfigurations/TerasologyPC__2nd_client_for_mac.xml +++ b/.idea/runConfigurations/TerasologyPC__2nd_client_for_mac.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__3rd_client_.xml b/.idea/runConfigurations/TerasologyPC__3rd_client_.xml index 0fe72e7ce39..d061cac83df 100644 --- a/.idea/runConfigurations/TerasologyPC__3rd_client_.xml +++ b/.idea/runConfigurations/TerasologyPC__3rd_client_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__CR_enabled_.xml b/.idea/runConfigurations/TerasologyPC__CR_enabled_.xml index ea0a5ffb0ef..c3bce539c58 100644 --- a/.idea/runConfigurations/TerasologyPC__CR_enabled_.xml +++ b/.idea/runConfigurations/TerasologyPC__CR_enabled_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__EXTREME_8GB_.xml b/.idea/runConfigurations/TerasologyPC__EXTREME_8GB_.xml index 72c21409742..99fd1f5ddf0 100644 --- a/.idea/runConfigurations/TerasologyPC__EXTREME_8GB_.xml +++ b/.idea/runConfigurations/TerasologyPC__EXTREME_8GB_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__Headless_.xml b/.idea/runConfigurations/TerasologyPC__Headless_.xml index 66e03af380c..f94ff517d70 100644 --- a/.idea/runConfigurations/TerasologyPC__Headless_.xml +++ b/.idea/runConfigurations/TerasologyPC__Headless_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__Java_FlightRecorder_.xml b/.idea/runConfigurations/TerasologyPC__Java_FlightRecorder_.xml index b2996206afd..c512a4b9fc9 100644 --- a/.idea/runConfigurations/TerasologyPC__Java_FlightRecorder_.xml +++ b/.idea/runConfigurations/TerasologyPC__Java_FlightRecorder_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__Splash_disabled_.xml b/.idea/runConfigurations/TerasologyPC__Splash_disabled_.xml index b65baca392a..9f4c016106c 100644 --- a/.idea/runConfigurations/TerasologyPC__Splash_disabled_.xml +++ b/.idea/runConfigurations/TerasologyPC__Splash_disabled_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__load_latest_.xml b/.idea/runConfigurations/TerasologyPC__load_latest_.xml index 25279eef250..c470a3742c3 100644 --- a/.idea/runConfigurations/TerasologyPC__load_latest_.xml +++ b/.idea/runConfigurations/TerasologyPC__load_latest_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__no_audio_.xml b/.idea/runConfigurations/TerasologyPC__no_audio_.xml index 0b74c94fa5f..3e24aec53de 100644 --- a/.idea/runConfigurations/TerasologyPC__no_audio_.xml +++ b/.idea/runConfigurations/TerasologyPC__no_audio_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__no_saves_.xml b/.idea/runConfigurations/TerasologyPC__no_saves_.xml index adcd06029b9..bfdb2f76073 100644 --- a/.idea/runConfigurations/TerasologyPC__no_saves_.xml +++ b/.idea/runConfigurations/TerasologyPC__no_saves_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__permissive_security_.xml b/.idea/runConfigurations/TerasologyPC__permissive_security_.xml index 5a4862eb803..0c2abcfed8c 100644 --- a/.idea/runConfigurations/TerasologyPC__permissive_security_.xml +++ b/.idea/runConfigurations/TerasologyPC__permissive_security_.xml @@ -21,6 +21,7 @@ \ No newline at end of file diff --git a/.idea/runConfigurations/TerasologyPC__recreate_latest_.xml b/.idea/runConfigurations/TerasologyPC__recreate_latest_.xml index 1fe1aaf7c1d..1ccd2ee9989 100644 --- a/.idea/runConfigurations/TerasologyPC__recreate_latest_.xml +++ b/.idea/runConfigurations/TerasologyPC__recreate_latest_.xml @@ -7,6 +7,7 @@ \ No newline at end of file From 2b2e6b3812598074b62ef5f480a102ca91344a35 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 4 Feb 2021 13:46:20 -0800 Subject: [PATCH 203/259] feat(JOML): migrate CanvasImpl (#4464) --- .../rendering/nui/CanvasUtility.java | 16 +++++------ .../nui/internal/TerasologyCanvasImpl.java | 28 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/engine/src/main/java/org/terasology/rendering/nui/CanvasUtility.java b/engine/src/main/java/org/terasology/rendering/nui/CanvasUtility.java index 8df1ea6ce4c..5a46ec38cb4 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/CanvasUtility.java +++ b/engine/src/main/java/org/terasology/rendering/nui/CanvasUtility.java @@ -15,11 +15,11 @@ */ package org.terasology.rendering.nui; +import org.joml.Quaternionfc; +import org.joml.Vector2ic; +import org.joml.Vector3fc; import org.terasology.assets.ResourceUrn; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Rect2i; -import org.terasology.math.geom.Vector3f; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.Canvas; import org.terasology.nui.SubRegion; import org.terasology.rendering.assets.material.Material; @@ -36,7 +36,7 @@ public final class CanvasUtility { private CanvasUtility() { } - public static void drawMesh(Canvas canvas, Mesh mesh, Texture texture, Rect2i region, Quat4f rotation, Vector3f offset, float scale) { + public static void drawMesh(Canvas canvas, Mesh mesh, Texture texture, Rectanglei region, Quaternionfc rotation, Vector3fc offset, float scale) { // TODO: Find a way to abstractly implement drawMesh in NUI if (!(canvas instanceof TerasologyCanvasImpl)) { @@ -46,7 +46,7 @@ public static void drawMesh(Canvas canvas, Mesh mesh, Texture texture, Rect2i re ((TerasologyCanvasImpl) canvas).drawMesh(mesh, texture, region, rotation, offset, scale); } - public static void drawMesh(Canvas canvas, Mesh mesh, Material material, Rect2i region, Quat4f rotation, Vector3f offset, float scale) { + public static void drawMesh(Canvas canvas, Mesh mesh, Material material, Rectanglei region, Quaternionfc rotation, Vector3fc offset, float scale) { // TODO: Find a way to abstractly implement drawMesh in NUI if (!(canvas instanceof TerasologyCanvasImpl)) { @@ -56,7 +56,7 @@ public static void drawMesh(Canvas canvas, Mesh mesh, Material material, Rect2i ((TerasologyCanvasImpl) canvas).drawMesh(mesh, material, region, rotation, offset, scale); } - public static void drawMaterial(Canvas canvas, Material material, Rect2i region) { + public static void drawMaterial(Canvas canvas, Material material, Rectanglei region) { // TODO: Find a way to abstractly implement drawMaterial in NUI if (!(canvas instanceof TerasologyCanvasImpl)) { @@ -66,7 +66,7 @@ public static void drawMaterial(Canvas canvas, Material material, Rect2i region) ((TerasologyCanvasImpl) canvas).drawMaterial(material, region); } - public static SubRegion subRegionFBO(Canvas canvas, ResourceUrn uri, BaseVector2i size) { + public static SubRegion subRegionFBO(Canvas canvas, ResourceUrn uri, Vector2ic size) { // TODO: Find a way to abstractly implement subRegionFBO in NUI if (!(canvas instanceof TerasologyCanvasImpl)) { diff --git a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java index 2b0b2943376..731976bf419 100644 --- a/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java +++ b/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.rendering.nui.internal; -import org.terasology.joml.geom.Rectanglei; +import org.joml.Quaternionfc; +import org.joml.Vector2ic; +import org.joml.Vector3fc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.assets.ResourceUrn; @@ -11,11 +13,7 @@ import org.terasology.context.Context; import org.terasology.engine.Time; import org.terasology.input.InputSystem; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.BaseVector2i; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Rect2i; -import org.terasology.math.geom.Vector3f; +import org.terasology.joml.geom.Rectanglei; import org.terasology.nui.SubRegion; import org.terasology.nui.UITextureRegion; import org.terasology.nui.canvas.CanvasImpl; @@ -77,14 +75,14 @@ protected long getGameTimeInMs() { } //NOTE: now only accessible via CanvasUtility - public SubRegion subRegionFBO(ResourceUrn uri, BaseVector2i size) { + public SubRegion subRegionFBO(ResourceUrn uri, Vector2ic size) { return new SubRegionFBOImpl(uri, size); } // NOTE: drawMaterial and drawMesh can now only be accessed through CanvasUtility - public void drawMaterial(Material material, Rect2i region) { + public void drawMaterial(Material material, Rectanglei region) { if (material.isRenderable()) { - Rectanglei drawRegion = relativeToAbsolute(JomlUtil.from(region)); + Rectanglei drawRegion = relativeToAbsolute(region); if (!state.cropRegion.intersectsRectangle(drawRegion)) { return; } @@ -94,7 +92,7 @@ public void drawMaterial(Material material, Rect2i region) { } } - public void drawMesh(Mesh mesh, Material material, Rect2i region, Quat4f rotation, Vector3f offset, float scale) { + public void drawMesh(Mesh mesh, Material material, Rectanglei region, Quaternionfc rotation, Vector3fc offset, float scale) { if (material == null) { logger.warn("Attempted to draw with nonexistent material"); return; @@ -104,17 +102,17 @@ public void drawMesh(Mesh mesh, Material material, Rect2i region, Quat4f rotatio return; } - Rectanglei drawRegion = relativeToAbsolute(JomlUtil.from(region)); + Rectanglei drawRegion = relativeToAbsolute(region); if (!state.cropRegion.intersectsRectangle(drawRegion)) { return; } ((TerasologyCanvasRenderer) renderer).drawMesh( mesh, material, drawRegion, drawRegion.intersection(state.cropRegion), - JomlUtil.from(rotation), JomlUtil.from(offset), scale, state.getAlpha()); + rotation, offset, scale, state.getAlpha()); } - public void drawMesh(Mesh mesh, UITextureRegion texture, Rect2i region, Quat4f rotation, Vector3f offset, float scale) { + public void drawMesh(Mesh mesh, UITextureRegion texture, Rectanglei region, Quaternionfc rotation, Vector3fc offset, float scale) { meshMat.setTexture("texture", ((TextureRegion)texture).getTexture()); drawMesh(mesh, meshMat, region, rotation, offset, scale); } @@ -130,10 +128,10 @@ private final class SubRegionFBOImpl implements SubRegion { private FrameBufferObject fbo; private CanvasState previousState; - private SubRegionFBOImpl(ResourceUrn uri, BaseVector2i size) { + private SubRegionFBOImpl(ResourceUrn uri, Vector2ic size) { previousState = state; - fbo = ((TerasologyCanvasRenderer)renderer).getFBO(uri, JomlUtil.from(size)); + fbo = ((TerasologyCanvasRenderer)renderer).getFBO(uri, size); state = new CanvasState(state, new Rectanglei(0, 0, size.x(), size.y())); fbo.bindFrame(); } From 412c87d0c1de1ab0256e491c3ac4daf0fbfa9b06 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 5 Feb 2021 06:23:34 -0800 Subject: [PATCH 204/259] feat(JOML): migrate EntityPool (#4461) --- .../entitySystem/entity/EntityPool.java | 26 ------------- .../entity/internal/PojoEntityManager.java | 17 --------- .../entity/internal/PojoEntityPool.java | 37 +++++-------------- .../entity/internal/PojoSectorManager.java | 17 --------- 4 files changed, 10 insertions(+), 87 deletions(-) diff --git a/engine/src/main/java/org/terasology/entitySystem/entity/EntityPool.java b/engine/src/main/java/org/terasology/entitySystem/entity/EntityPool.java index 5ee1eb72b93..1a4a43161e0 100644 --- a/engine/src/main/java/org/terasology/entitySystem/entity/EntityPool.java +++ b/engine/src/main/java/org/terasology/entitySystem/entity/EntityPool.java @@ -19,8 +19,6 @@ import org.joml.Vector3fc; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.prefab.Prefab; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; public interface EntityPool { @@ -88,41 +86,17 @@ public interface EntityPool { // TODO: Review. Probably better to move these into a static helper - /** - * @return A new entity, based on the given prefab, at the desired position - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #create(String,Vector3fc)}. - */ - @Deprecated - EntityRef create(String prefab, Vector3f position); - /** * @return A new entity, based on the given prefab, at the desired position */ EntityRef create(String prefab, Vector3fc position); - /** - * @return A new entity, based on the given prefab, at the desired position - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #create(Prefab,Vector3fc)}. - */ - @Deprecated - EntityRef create(Prefab prefab, Vector3f position); /** * @return A new entity, based on the given prefab, at the desired position */ EntityRef create(Prefab prefab, Vector3fc position); - /** - * @return A new entity, based on the given prefab, at the desired position, and with the desired rotation - * @deprecated This method is scheduled for removal in an upcoming version. - * Use the JOML implementation instead: {@link #create(Prefab,Vector3fc,Quaternionfc)}. - */ - @Deprecated - EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation); - - /** * @return A new entity, based on the given prefab, at the desired position, and with the desired rotation */ diff --git a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityManager.java b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityManager.java index a188216e82c..f98db3f94ca 100644 --- a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityManager.java +++ b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityManager.java @@ -43,8 +43,6 @@ import org.terasology.entitySystem.prefab.PrefabManager; import org.terasology.entitySystem.sectors.SectorSimulationComponent; import org.terasology.game.GameManifest; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.world.internal.WorldInfo; @@ -213,26 +211,11 @@ public EntityRef create(String prefabName) { return getCurrentWorldPool().create(prefabName); } - @Override - public EntityRef create(Prefab prefab, Vector3f position) { - return getCurrentWorldPool().create(prefab, position); - } - - @Override - public EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation) { - return getCurrentWorldPool().create(prefab, position, rotation); - } - @Override public EntityRef create(Prefab prefab, Vector3fc position, Quaternionfc rotation) { return getCurrentWorldPool().create(prefab, position, rotation); } - @Override - public EntityRef create(String prefab, Vector3f position) { - return getCurrentWorldPool().create(prefab, position); - } - @Override public EntityRef create(Prefab prefab, Vector3fc position) { return getCurrentWorldPool().create(prefab, position); diff --git a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java index 2c84b40dd99..f8ab1740dde 100644 --- a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java +++ b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoEntityPool.java @@ -29,9 +29,6 @@ import org.terasology.entitySystem.event.internal.EventSystem; import org.terasology.entitySystem.prefab.Prefab; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import java.util.Arrays; import java.util.Collections; @@ -66,7 +63,7 @@ public void clear() { @Override public EntityRef create() { - return create((Prefab) null, (Vector3f) null, null); + return create((Prefab) null, (Vector3fc) null, null); } @Override @@ -92,42 +89,28 @@ public EntityRef create(String prefabName) { return create(prefabName, null, null); } - @Override - public EntityRef create(String prefabName, Vector3f position) { - return create(prefabName, position, null); - } @Override public EntityRef create(String prefabName, Vector3fc position) { - return create(prefabName, JomlUtil.from(position), null); - } - - @Override - public EntityRef create(Prefab prefab, Vector3f position) { - return create(prefab, position, null); + return create(prefabName, position, null); } @Override public EntityRef create(Prefab prefab, Vector3fc position) { - return create(prefab, JomlUtil.from(position), null); + return create(prefab, position, null); } @Override public EntityRef create(Prefab prefab) { - return create(prefab, (Vector3f) null, null); - } - - @Override - public EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation) { - return create(prefab, position, rotation, true); + return create(prefab, (Vector3fc) null, null); } @Override public EntityRef create(Prefab prefab, Vector3fc position, Quaternionfc rotation) { - return create(prefab, JomlUtil.from(position), JomlUtil.from(rotation), true); + return create(prefab, position, rotation, true); } - private EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation, boolean sendLifecycleEvents) { + private EntityRef create(Prefab prefab, Vector3fc position, Quaternionfc rotation, boolean sendLifecycleEvents) { EntityBuilder builder = newBuilder(prefab); builder.setSendLifecycleEvents(sendLifecycleEvents); @@ -138,20 +121,20 @@ private EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation, bool } if (position != null) { - loc.setWorldPosition(JomlUtil.from(position)); + loc.setWorldPosition(position); } if (rotation != null) { - loc.setWorldRotation(JomlUtil.from(rotation)); + loc.setWorldRotation(rotation); } return builder.build(); } - private EntityRef create(String prefabName, Vector3f position, Quat4f rotation) { + private EntityRef create(String prefabName, Vector3fc position, Quaternionfc rotation) { return create(prefabName, position, rotation, true); } - private EntityRef create(String prefabName, Vector3f position, Quat4f rotation, boolean sendLifecycleEvents) { + private EntityRef create(String prefabName, Vector3fc position, Quaternionfc rotation, boolean sendLifecycleEvents) { Prefab prefab; if (prefabName == null || prefabName.isEmpty()) { prefab = null; diff --git a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoSectorManager.java b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoSectorManager.java index 26f5074eaac..5e72ba8c103 100644 --- a/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoSectorManager.java +++ b/engine/src/main/java/org/terasology/entitySystem/entity/internal/PojoSectorManager.java @@ -23,8 +23,6 @@ import org.terasology.entitySystem.entity.EntityPool; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.prefab.Prefab; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; import java.util.ArrayList; import java.util.List; @@ -100,31 +98,16 @@ public EntityRef create(Prefab prefab) { return getPool().create(prefab); } - @Override - public EntityRef create(String prefab, Vector3f position) { - return getPool().create(prefab, position); - } - @Override public EntityRef create(String prefab, Vector3fc position) { return getPool().create(prefab, position); } - @Override - public EntityRef create(Prefab prefab, Vector3f position) { - return getPool().create(prefab, position); - } - @Override public EntityRef create(Prefab prefab, Vector3fc position) { return getPool().create(prefab, position); } - @Override - public EntityRef create(Prefab prefab, Vector3f position, Quat4f rotation) { - return getPool().create(prefab, position, rotation); - } - @Override public EntityRef create(Prefab prefab, Vector3fc position, Quaternionfc rotation) { return getPool().create(prefab, position, rotation); From 00f7e503a9b404acd91175994476153b1be424fc Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 5 Feb 2021 19:50:20 -0800 Subject: [PATCH 205/259] build: patch upgrade to gradle 6.8.2 (#4465) From the release notes: > fixes large performance regression when file system watching is enabled on macOs and Windows --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1c4bcc29e17..25d3265315f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 7feb8418b6c50926f9dfdf51e30b7de93d57d3ff Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 6 Feb 2021 00:38:55 -0800 Subject: [PATCH 206/259] build(PC): add gradle command-line option for max heap size (#4467) --- .../src/main/kotlin/org/terasology/gradology/exec.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt index dfa64e70afa..1f7fa41e948 100644 --- a/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt +++ b/buildSrc/src/main/kotlin/org/terasology/gradology/exec.kt @@ -9,9 +9,12 @@ import org.gradle.api.logging.Logging import org.gradle.api.plugins.JavaApplication import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.options.Option import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.the +const val DEFAULT_MAX_HEAP_SIZE = "3G" + private val logger: Logger = Logging.getLogger("org.tersology.gradology.exec") /** @@ -42,6 +45,11 @@ fun isMacOS() : Boolean { open class RunTerasology : JavaExec() { + @Option(option="max-heap", description="Set maximum heap size (-Xmx)") + override fun setMaxHeapSize(heapSize: String?) { + super.setMaxHeapSize(heapSize) + } + init { group = "terasology run" @@ -57,7 +65,7 @@ open class RunTerasology : JavaExec() { dependsOn(project.configurations.named("modules")) args("-homedir") - jvmArgs("-Xmx3072m") + maxHeapSize = DEFAULT_MAX_HEAP_SIZE if (isMacOS()) { args("-noSplash") From 43d41d17067366dcbdc92488bed2230c6202a8fe Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Sat, 6 Feb 2021 01:03:29 -0800 Subject: [PATCH 207/259] fix(ModuleManager): fix improperly-escaped spaces in module path (#4466) * chore(ModuleManager): make members final and other tidying * refactor(ModuleManager): factor out inner loop of loadModulesFromClassPath * fix(ModuleManager): get the jar url in a way less prone to string-escaping problems * chore(ModuleManager): let ModuleLoader do the metadata parsing things * test(ModuleManager): parameterize test * refactor(ModuleManager): consolidate error handling Fixes #4407 --- .../engine/module/ModuleManagerTest.java | 46 +++++++++++ .../testmessy-1.0.0-SNAPSHOT.jar | Bin 0 -> 567 bytes .../module/testdummy-1.0.0-SNAPSHOT.jar | Bin 0 -> 567 bytes .../engine/module/ModuleManagerImpl.java | 76 ++++++++---------- 4 files changed, 78 insertions(+), 44 deletions(-) create mode 100644 engine-tests/src/test/java/org/terasology/engine/module/ModuleManagerTest.java create mode 100644 engine-tests/src/test/resources/org/terasology/engine/module/messy-name-directory & $t#f/testmessy-1.0.0-SNAPSHOT.jar create mode 100644 engine-tests/src/test/resources/org/terasology/engine/module/testdummy-1.0.0-SNAPSHOT.jar diff --git a/engine-tests/src/test/java/org/terasology/engine/module/ModuleManagerTest.java b/engine-tests/src/test/java/org/terasology/engine/module/ModuleManagerTest.java new file mode 100644 index 00000000000..fcfd26250dd --- /dev/null +++ b/engine-tests/src/test/java/org/terasology/engine/module/ModuleManagerTest.java @@ -0,0 +1,46 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.module; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.terasology.module.ModuleLoader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.terasology.engine.TerasologyConstants.MODULE_INFO_FILENAME; + +public class ModuleManagerTest { + @ParameterizedTest + @ValueSource(strings = { + "testdummy-1.0.0-SNAPSHOT.jar", + "messy-name-directory & $t#f/testmessy-1.0.0-SNAPSHOT.jar" + }) + void testLoadModuleFromURL(String jarLocation) throws IOException, URISyntaxException { + ModuleManagerImpl mm = new ThisModuleManager(""); + ModuleLoader loader = new ModuleLoader(); + loader.setModuleInfoPath(MODULE_INFO_FILENAME); + + URL url = getClass().getResource("/org/terasology/engine/module/" + jarLocation); + assumeTrue(url != null, "test resource not found:" + jarLocation); + URL jarUrl = new URL("jar", null, url.toString() + "!/" + MODULE_INFO_FILENAME); + + assertNotNull(mm.load(loader, jarUrl)); + } + + private static class ThisModuleManager extends ModuleManagerImpl { + ThisModuleManager(String masterServerAddress) { + super(masterServerAddress); + } + + @Override + void loadModulesFromClassPath() { + // empty implementation so it doesn't fire everything off during the constructor + } + } +} diff --git a/engine-tests/src/test/resources/org/terasology/engine/module/messy-name-directory & $t#f/testmessy-1.0.0-SNAPSHOT.jar b/engine-tests/src/test/resources/org/terasology/engine/module/messy-name-directory & $t#f/testmessy-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..ddf513e589972b195f9aa74dac57f603db15ddae GIT binary patch literal 567 zcmWIWW@h1HVBp|j$mmiEVgLdr5CH_7K6 ziy$lXb@cOea}5sB^L6{|d*-x{x31nrUT7F zpdogQ3=BZGFy!W^l;))Bl~k1Y`WyNkb`W^;w`=Na0mT2e&73>;XI4kl$G5UuzZ)(zcHUMNd{KCk=M}HJIr-bKhyPty{Yw6u zzIfCdNyeOtl&8$AT>Xs2&UO1Xp0~DpbbaQ(=;|5XMo+Kq3x0I!lHo7QhGioDk6igv z51(kx&EU9LJK?y7*4Hx~SA{2cD;@}KdE_BEztT^ms(bSj6 ziy$lXb@cOea}5sB^L6{|d*-x{x31nrUT7F zpdogQ3=BZGFy!W^l;))Bl~k1Y`WyNkb`W^;w`=Na0mT2e&73>;XI4kl$G5UuzZ)(zcHUMNd{KCk=M}HJIr-bKhyPty{Yw6u zzIfCdNyeOtl&8$AT>Xs2&UO1Xp0~DpbbaQ(=;|5XMo+Kq3x0I!lHo7QhGioDk6igv z51(kx&EU9LJK?y7*4Hx~SA{2cD;@}KdE_BEztT^ms(bSj> classesOnClasspathsToAddT /** * Overrides modules in modules/ with those specified via -classpath in the JVM */ - private void loadModulesFromClassPath() { + void loadModulesFromClassPath() { ClassLoader classLoader = ClassLoader.getSystemClassLoader(); ModuleLoader loader = new ModuleLoader(metadataReader); Enumeration moduleInfosInClassPath; @@ -136,49 +135,38 @@ private void loadModulesFromClassPath() { try { moduleInfosInClassPath = classLoader.getResources(TerasologyConstants.MODULE_INFO_FILENAME.toString()); } catch (IOException e) { - logger.warn("Failed to search for classpath modules: {}", e); + logger.warn("Failed to search for classpath modules:", e); return; } for (URL url : Collections.list(moduleInfosInClassPath)) { - if (!url.getProtocol().equalsIgnoreCase("jar")) { + Module module; + try { + module = load(loader, url); + } catch (ClassCastException | IOException | URISyntaxException e) { + logger.warn("Failed to load classpath module {}", url, e); continue; } + if (module != null) { + registry.add(module); + logger.info("Loaded module {} from class path at {}", module, url.getFile()); + } + } + } - try (Reader reader = new InputStreamReader(url.openStream(), TerasologyConstants.CHARSET)) { - ModuleMetadata metaData = metadataReader.read(reader); - String displayName = metaData.getDisplayName().toString(); - Name id = metaData.getId(); - - // if the display name is empty or the id is null, this probably isn't a Terasology module - if (null == id || displayName.equalsIgnoreCase("")) { - logger.warn("Found a module-like JAR on the class path with no id or display name. Skipping"); - logger.warn("{}", url); - continue; - } - - logger.info("Loading module {} from class path at {}", displayName, url.getFile()); - - // the url contains a protocol, and points to the module.txt - // we need to trim both of those away to get the module's path - String targetFile = url.getFile() - .replace("file:", "") - .replace("!/" + TerasologyConstants.MODULE_INFO_FILENAME, "") - .replace("/" + TerasologyConstants.MODULE_INFO_FILENAME, ""); - - // Windows specific check - Path doesn't like /C:/... style Strings indicating files - if (targetFile.matches("/[a-zA-Z]:.*")) { - targetFile = targetFile.substring(1); - } + Module load(ModuleLoader loader, URL url) throws IOException, URISyntaxException { + JarURLConnection connection = (JarURLConnection) url.openConnection(); + Path jarPath = Paths.get(connection.getJarFileURL().toURI()); - Path path = Paths.get(targetFile); + Module module = loader.load(jarPath); - Module module = loader.load(path); - registry.add(module); - } catch (IOException e) { - logger.warn("Failed to load module.txt for classpath module {}", url); - } + // if the display name is empty or the id is null, this probably isn't a Terasology module + if (null == module.getId() || module.getMetadata().getDisplayName().toString().isEmpty()) { + logger.warn("Found a module-like JAR on the class path with no id or display name. Skipping {}", url); + return null; } + + return module; } private void setupSandbox() { @@ -219,9 +207,9 @@ public ModuleEnvironment loadEnvironment(Set modules, boolean asPrimary) ModuleEnvironment newEnvironment; boolean permissiveSecurityEnabled = Boolean.parseBoolean(System.getProperty(SystemConfig.PERMISSIVE_SECURITY_ENABLED_PROPERTY)); if (permissiveSecurityEnabled) { - newEnvironment = new ModuleEnvironment(finalModules, wrappingPermissionProviderFactory, Collections.emptyList()); + newEnvironment = new ModuleEnvironment(finalModules, wrappingPermissionProviderFactory, Collections.emptyList()); } else { - newEnvironment = new ModuleEnvironment(finalModules, permissionProviderFactory, Collections.emptyList()); + newEnvironment = new ModuleEnvironment(finalModules, permissionProviderFactory, Collections.emptyList()); } if (asPrimary) { environment = newEnvironment; From 33205c6518cee60bb96a839fb1b5d215cde861c2 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 6 Feb 2021 03:06:44 -0800 Subject: [PATCH 208/259] feat(JOML): migrate AbstractFullWorldview (#4468) --- .../propagation/AbstractFullWorldView.java | 7 ++-- .../propagation/PropagatorWorldView.java | 32 ------------------- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java b/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java index b1871246913..e9b3248b95e 100644 --- a/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/AbstractFullWorldView.java @@ -17,7 +17,6 @@ import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; import org.terasology.world.block.Block; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; @@ -44,7 +43,7 @@ public AbstractFullWorldView(ChunkProvider chunkProvider) { * @return The chunk for that position */ private Chunk getChunk(Vector3ic pos) { - return chunkProvider.getChunk(JomlUtil.from(Chunks.toChunkPos(pos, new Vector3i()))); + return chunkProvider.getChunk(Chunks.toChunkPos(pos, new Vector3i())); } @Override @@ -70,7 +69,7 @@ public void setValueAt(Vector3ic pos, byte value) { setValueAt(getChunk(pos), Chunks.toRelative(pos, new Vector3i()), value); BlockRegion chunkRegion = new BlockRegion(pos).expand(1, 1, 1); for (Vector3ic affectedChunkPos : Chunks.toChunkRegion(chunkRegion, chunkRegion)) { - Chunk dirtiedChunk = chunkProvider.getChunk(JomlUtil.from(affectedChunkPos)); + Chunk dirtiedChunk = chunkProvider.getChunk(affectedChunkPos); if (dirtiedChunk != null) { dirtiedChunk.setDirty(true); } @@ -88,7 +87,7 @@ public void setValueAt(Vector3ic pos, byte value) { @Override public Block getBlockAt(Vector3ic pos) { - CoreChunk chunk = chunkProvider.getChunk(JomlUtil.from(Chunks.toChunkPos(pos, new Vector3i()))); + CoreChunk chunk = chunkProvider.getChunk(Chunks.toChunkPos(pos, new Vector3i())); if (chunk != null) { return chunk.getBlock(Chunks.toRelative(pos, new Vector3i())); } diff --git a/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java b/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java index 448a68f076a..a601ac2b9d3 100644 --- a/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java +++ b/engine/src/main/java/org/terasology/world/propagation/PropagatorWorldView.java @@ -16,8 +16,6 @@ package org.terasology.world.propagation; import org.joml.Vector3ic; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; /** @@ -27,46 +25,16 @@ public interface PropagatorWorldView { byte UNAVAILABLE = -1; - /** - * @return The value of interest at pos, or {@link #UNAVAILABLE} if out of bounds - * - * @deprecated use {@link #getValueAt(Vector3ic)} instead - */ - @Deprecated - default byte getValueAt(Vector3i pos) { - return getValueAt(JomlUtil.from(pos)); - } - /** * @return The value of interest at pos, or {@link #UNAVAILABLE} if out of bounds */ byte getValueAt(Vector3ic pos); - /** - * @param value A new value at pos. - * - * @deprecated use {@link #setValueAt(Vector3ic, byte)} instead - */ - @Deprecated - default void setValueAt(Vector3i pos, byte value) { - setValueAt(JomlUtil.from(pos), value); - }; - /** * @param value A new value at pos. */ void setValueAt(Vector3ic pos, byte value); - /** - * @return The block at pos, or null if out of bounds - * - * @deprecated use {@link #getBlockAt(Vector3ic)} instead - */ - @Deprecated - default Block getBlockAt(Vector3i pos) { - return getBlockAt(JomlUtil.from(pos)); - }; - /** * @return The block at pos, or null if out of bounds */ From 67cb9bdc3ff6af73117bb63447024003664a88b3 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 6 Feb 2021 04:32:09 -0800 Subject: [PATCH 209/259] feat(JOML): migrate and cleanup EntityAwareWorldProvider (#4456) Co-authored-by: Tobias Nett --- .../network/internal/ServerImpl.java | 2 +- .../NetEntityRefTypeHandler.java | 3 +- .../terasology/world/BlockEntityRegistry.java | 102 +--------------- .../org/terasology/world/OnChangedBlock.java | 3 +- .../internal/EntityAwareWorldProvider.java | 109 ++++++------------ 5 files changed, 40 insertions(+), 179 deletions(-) diff --git a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java index a332e2ae9b8..d89919093e4 100644 --- a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java +++ b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java @@ -367,7 +367,7 @@ private void updateEntity(NetData.UpdateEntityMessage updateEntity) { entitySerializer.deserializeOnto(currentEntity, updateEntity.getEntity()); BlockComponent blockComponent = currentEntity.getComponent(BlockComponent.class); if (blockComponent != null && !blockEntityBefore) { - if (!blockEntityRegistry.getExistingBlockEntityAt(blockComponent.position).equals(currentEntity)) { + if (!blockEntityRegistry.getExistingBlockEntityAt(blockComponent.getPosition(new Vector3i())).equals(currentEntity)) { logger.error("Failed to associated new block entity"); } } diff --git a/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java b/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java index fc211051225..54afa67227f 100644 --- a/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java +++ b/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java @@ -18,6 +18,7 @@ import gnu.trove.list.TIntList; import org.terasology.entitySystem.entity.EntityRef; +import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; import org.terasology.network.NetworkComponent; import org.terasology.network.internal.NetworkSystemImpl; @@ -65,7 +66,7 @@ public Optional deserialize(PersistedData data) { if (array.isNumberArray() && array.size() == 3) { TIntList items = data.getAsArray().getAsIntegerArray(); Vector3i pos = new Vector3i(items.get(0), items.get(1), items.get(2)); - return Optional.ofNullable(blockEntityRegistry.getBlockEntityAt(pos)); + return Optional.ofNullable(blockEntityRegistry.getBlockEntityAt(JomlUtil.from(pos))); } } if (data.isNumber()) { diff --git a/engine/src/main/java/org/terasology/world/BlockEntityRegistry.java b/engine/src/main/java/org/terasology/world/BlockEntityRegistry.java index 7f633d269cd..625e9c90a3d 100644 --- a/engine/src/main/java/org/terasology/world/BlockEntityRegistry.java +++ b/engine/src/main/java/org/terasology/world/BlockEntityRegistry.java @@ -19,8 +19,6 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.Component; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.world.block.Block; /** @@ -36,23 +34,10 @@ public interface BlockEntityRegistry { * This has implications for blocks being placed onto that position and destroyed at that position. * * @param blockPosition The position to set the new entity in - * @param bockEntity The new entity to set + * @param blockEntity The new entity to set * @return The previous entity at the location, or a null entity if one didn't exist yet. */ - EntityRef setPermanentBlockEntity(Vector3i blockPosition, EntityRef bockEntity); - - /** - * This method returns the block entity at the given location, but will not produce a temporary entity if - * one isn't currently in memory. - * - * @param blockPosition absolute position of the block - * @return The block entity for the location if it exists, or the null entity - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getExistingBlockEntityAt(Vector3ic)}. - **/ - @Deprecated - EntityRef getExistingBlockEntityAt(Vector3i blockPosition); - + EntityRef setPermanentBlockEntity(Vector3ic blockPosition, EntityRef blockEntity); /** * This method returns the block entity at the given location, but will not produce a temporary entity if @@ -63,20 +48,6 @@ public interface BlockEntityRegistry { */ EntityRef getExistingBlockEntityAt(Vector3ic blockPosition); - - /** - * This method is the same as setBlock, except if the old and new block types are part of the same family the - * entity will be force updated (usually they are not in this situation). - * - * @param position absolute position of the block in world space - * @param type type of block - * @return The previous block type, or null if the change failed due to the chunk not being available - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setBlockForceUpdateEntity(Vector3ic, Block)}. - */ - @Deprecated - Block setBlockForceUpdateEntity(Vector3i position, Block type); - /** * This method is the same as setBlock, except if the old and new block types are part of the same family the * entity will be force updated (usually they are not in this situation). @@ -87,20 +58,6 @@ public interface BlockEntityRegistry { */ Block setBlockForceUpdateEntity(Vector3ic position, Block type); - - /** - * This method is the same as setBlock, except the specified components are not altered during the update - * - * @param position absolute position of the block in world space - * @param type type of block - * @param components components that are assigned to the block - * @return The previous block type, or null if the change failed due to the chunk not being available - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #setBlockRetainComponent(Vector3ic, Block, Class[])}. - **/ - @Deprecated - Block setBlockRetainComponent(Vector3i position, Block type, Class... components); - /** * This method is the same as setBlock, except the specified components are not altered during the update * @@ -111,18 +68,6 @@ public interface BlockEntityRegistry { */ Block setBlockRetainComponent(Vector3ic position, Block type, Class... components); - - /** - * retrieves an EntityRef for a given block. - * - * @param position absolute position of the block in world space - * @return The block entity for the location, creating it if it doesn't exist - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getBlockEntityAt(Vector3fc)}. - **/ - @Deprecated - EntityRef getBlockEntityAt(Vector3f position); - /** * retrieves an {@link EntityRef} for a given block. * @param position absolute position of the block in world space rounded {@link org.joml.RoundingMode#HALF_UP} @@ -130,17 +75,6 @@ public interface BlockEntityRegistry { **/ EntityRef getBlockEntityAt(Vector3fc position); - /** - * retrieves an EntityRef for a given block. - * - * @param blockPosition absolute position of the block in world place - * @return The block entity for the location, creating it if it doesn't exist - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getBlockEntityAt(Vector3ic)}. - */ - @Deprecated - EntityRef getBlockEntityAt(Vector3i blockPosition); - /** * retrieves an EntityRef for a given block. * @@ -149,16 +83,6 @@ public interface BlockEntityRegistry { */ EntityRef getBlockEntityAt(Vector3ic blockPosition); - /** - * retrieves an entity associated with the given block else return a {@link EntityRef#NULL} - * @param blockPosition position of the block in world position. - * @return The block controller entity for this location, or block entity if it exists. - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getExistingEntityAt(Vector3ic)}. - */ - @Deprecated - EntityRef getExistingEntityAt(Vector3i blockPosition); - /** * retrieves an entity associated with the given block else return a {@link EntityRef#NULL} * @param blockPosition position of the block in world position. @@ -166,16 +90,6 @@ public interface BlockEntityRegistry { */ EntityRef getExistingEntityAt(Vector3ic blockPosition); - /** - * retrieves an entity associated with the given block else create a new entity - * @param blockPosition absolute position of the block. - * @return The block {@link EntityRef} for this location. - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #getEntityAt(Vector3ic)}. - */ - @Deprecated - EntityRef getEntityAt(Vector3i blockPosition); - /** * retrieves an entity associated with the given block else create a new entity * @param blockPosition absolute position of the block in. @@ -183,18 +97,6 @@ public interface BlockEntityRegistry { */ EntityRef getEntityAt(Vector3ic blockPosition); - /** - * tell if the entity assigned to a given block is permanent. non-permanent - * block entities are cleaned up at the end of the update. - * - * @param blockPos absolute position of the block. - * @return Whether the entity at this position is permanent - * @deprecated This is scheduled for removal in an upcoming version - * method will be replaced with JOML implementation {@link #hasPermanentBlockEntity(Vector3ic)}. - **/ - @Deprecated - boolean hasPermanentBlockEntity(Vector3i blockPos); - /** * tell if the entity assigned to a given block is permanent. non-permanent * block entities are cleaned up at the end of the update. diff --git a/engine/src/main/java/org/terasology/world/OnChangedBlock.java b/engine/src/main/java/org/terasology/world/OnChangedBlock.java index 91ad53e1463..a5c2afc12a1 100644 --- a/engine/src/main/java/org/terasology/world/OnChangedBlock.java +++ b/engine/src/main/java/org/terasology/world/OnChangedBlock.java @@ -17,6 +17,7 @@ package org.terasology.world; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.event.Event; import org.terasology.world.block.Block; @@ -29,7 +30,7 @@ public class OnChangedBlock implements Event { private Block newType; private Vector3i blockPosition; - public OnChangedBlock(Vector3i pos, Block newType, Block oldType) { + public OnChangedBlock(Vector3ic pos, Block newType, Block oldType) { this.blockPosition = new Vector3i(pos); this.oldType = oldType; this.newType = newType; diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index 5841dec0987..2fe859da2be 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -21,7 +21,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import org.joml.RoundingMode; +import org.joml.Vector3f; import org.joml.Vector3fc; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,9 +48,6 @@ import org.terasology.entitySystem.systems.UpdateSubscriberSystem; import org.terasology.logic.common.RetainComponentsComponent; import org.terasology.logic.location.LocationComponent; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.network.NetworkComponent; import org.terasology.reflection.metadata.FieldMetadata; @@ -58,7 +58,6 @@ import org.terasology.world.block.BlockRegion; import org.terasology.world.block.regions.BlockRegionComponent; -import java.math.RoundingMode; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -70,18 +69,17 @@ public class EntityAwareWorldProvider extends AbstractWorldProviderDecorator imp private static final Logger logger = LoggerFactory.getLogger(EntityAwareWorldProvider.class); private static final Set> COMMON_BLOCK_COMPONENTS = ImmutableSet.of(NetworkComponent.class, BlockComponent.class, LocationComponent.class); - private static final float BLOCK_REGEN_SECONDS = 4.0f; - private EngineEntityManager entityManager; + private final EngineEntityManager entityManager; // TODO: Perhaps a better datastructure for spatial lookups // TODO: Or perhaps a build in indexing system for entities - private Map blockEntityLookup = Maps.newHashMap(); + private final Map blockEntityLookup = Maps.newHashMap(); - private Map blockRegionLookup = Maps.newHashMap(); - private Map blockRegions = Maps.newHashMap(); + private final Map blockRegionLookup = Maps.newHashMap(); + private final Map blockRegions = Maps.newHashMap(); - private Set temporaryBlockEntities = Sets.newLinkedHashSet(); + private final Set temporaryBlockEntities = Sets.newLinkedHashSet(); public EntityAwareWorldProvider(WorldProviderCore base, Context context) { super(base); @@ -118,14 +116,14 @@ public void shutdown() { @Override public Block setBlock(Vector3ic pos, Block type) { if (GameThread.isCurrentThread()) { - EntityRef blockEntity = getBlockEntityAt(JomlUtil.from(pos)); + EntityRef blockEntity = getBlockEntityAt(pos); Block oldType = super.setBlock(pos, type); final Set> retainComponents = Optional.ofNullable(blockEntity.getComponent(RetainComponentsComponent.class)) .map(retainComponentsComponent -> retainComponentsComponent.components) .orElse(Collections.emptySet()); if (oldType != null) { - updateBlockEntity(blockEntity, JomlUtil.from(pos), oldType, type, false, retainComponents); + updateBlockEntity(blockEntity, pos, oldType, type, false, retainComponents); } return oldType; } @@ -150,7 +148,7 @@ public Map setBlocks(Map blocks) { Optional.ofNullable(blockEntity.getComponent(RetainComponentsComponent.class)) .map(retainComponentsComponent -> retainComponentsComponent.components) .orElse(Collections.emptySet()); - updateBlockEntity(blockEntity, JomlUtil.from(vec), oldBlocks.get(vec), blocks.get(vec), false, retainComponents); + updateBlockEntity(blockEntity, vec, oldBlocks.get(vec), blocks.get(vec), false, retainComponents); } } return oldBlocks; @@ -158,12 +156,6 @@ public Map setBlocks(Map blocks) { return null; } - @Override - @SafeVarargs - public final Block setBlockRetainComponent(Vector3i pos, Block type, Class... components) { - return setBlockRetainComponent(JomlUtil.from(pos), type, components); - } - @Override @SafeVarargs public final Block setBlockRetainComponent(Vector3ic position, Block type, Class... components) { @@ -171,14 +163,14 @@ public final Block setBlockRetainComponent(Vector3ic position, Block type, Class EntityRef blockEntity = getBlockEntityAt(position); Block oldType = super.setBlock(position, type); if (oldType != null) { - updateBlockEntity(blockEntity, JomlUtil.from(position), oldType, type, false, Sets.newHashSet(components)); + updateBlockEntity(blockEntity, position, oldType, type, false, Sets.newHashSet(components)); } return oldType; } return null; } - private void updateBlockEntity(EntityRef blockEntity, Vector3i pos, Block oldType, Block type, + private void updateBlockEntity(EntityRef blockEntity, Vector3ic pos, Block oldType, Block type, boolean forceEntityUpdate, Set> retainComponents) { if (type.isKeepActive()) { temporaryBlockEntities.remove(blockEntity); @@ -189,8 +181,8 @@ private void updateBlockEntity(EntityRef blockEntity, Vector3i pos, Block oldTyp updateBlockEntityComponents(blockEntity, oldType, type, retainComponents); } - OnChangedBlock changedEvent = new OnChangedBlock(JomlUtil.from(pos), type, oldType); - EntityRef regionEntity = blockRegionLookup.get(JomlUtil.from(pos)); + OnChangedBlock changedEvent = new OnChangedBlock(pos, type, oldType); + EntityRef regionEntity = blockRegionLookup.get(pos); if (regionEntity != null) { regionEntity.send(changedEvent); } @@ -198,10 +190,10 @@ private void updateBlockEntity(EntityRef blockEntity, Vector3i pos, Block oldTyp } @Override - public EntityRef setPermanentBlockEntity(Vector3i blockPosition, EntityRef blockEntity) { + public EntityRef setPermanentBlockEntity(Vector3ic blockPosition, EntityRef blockEntity) { if (GameThread.isCurrentThread()) { EntityRef oldEntity = getExistingBlockEntityAt(blockPosition); - blockEntityLookup.put(blockPosition, blockEntity); + blockEntityLookup.put(new Vector3i(blockPosition), blockEntity); temporaryBlockEntities.remove(blockEntity); return oldEntity; } @@ -209,56 +201,35 @@ public EntityRef setPermanentBlockEntity(Vector3i blockPosition, EntityRef block return EntityRef.NULL; } - @Override - public EntityRef getExistingBlockEntityAt(Vector3i blockPosition) { - return getExistingBlockEntityAt(JomlUtil.from(blockPosition)); - } - @Override public EntityRef getExistingBlockEntityAt(Vector3ic blockPosition) { if (GameThread.isCurrentThread()) { - EntityRef result = blockEntityLookup.get(JomlUtil.from(blockPosition)); + EntityRef result = blockEntityLookup.get(blockPosition); return (result == null) ? EntityRef.NULL : result; } logger.error("Attempted to get block entity off-thread"); return EntityRef.NULL; } - @Override - public Block setBlockForceUpdateEntity(Vector3i pos, Block type) { - return setBlockForceUpdateEntity(JomlUtil.from(pos), type); - } - @Override public Block setBlockForceUpdateEntity(Vector3ic position, Block type) { if (GameThread.isCurrentThread()) { EntityRef blockEntity = getBlockEntityAt(position); Block oldType = super.setBlock(position, type); if (oldType != null) { - updateBlockEntity(blockEntity, JomlUtil.from(position), oldType, type, true, Collections.>emptySet()); + updateBlockEntity(blockEntity, position, oldType, type, true, Collections.>emptySet()); } return oldType; } return null; } - @Override - public EntityRef getBlockEntityAt(Vector3f position) { - Vector3i pos = new Vector3i(position, RoundingMode.HALF_UP); - return getBlockEntityAt(pos); - } - @Override public EntityRef getBlockEntityAt(Vector3fc position) { - org.joml.Vector3i pos = new org.joml.Vector3i(position, org.joml.RoundingMode.HALF_UP); + Vector3i pos = new Vector3i(position, RoundingMode.HALF_UP); return getBlockEntityAt(pos); } - @Override - public EntityRef getBlockEntityAt(Vector3i blockPosition) { - return getBlockEntityAt(JomlUtil.from(blockPosition)); - } - @Override public EntityRef getBlockEntityAt(Vector3ic blockPosition) { if (GameThread.isCurrentThread()) { @@ -377,7 +348,7 @@ private void updateComponent(EntityRef blockEntity, Compon private EntityRef createBlockEntity(Vector3ic blockPosition, Block block) { EntityBuilder builder = entityManager.newBuilder(block.getPrefab().orElse(null)); - builder.addComponent(new LocationComponent(new org.joml.Vector3f(blockPosition))); + builder.addComponent(new LocationComponent(new Vector3f(blockPosition))); builder.addComponent(new BlockComponent(block, blockPosition)); boolean isTemporary = isTemporaryBlock(builder, block); if (!isTemporary && !builder.hasComponent(NetworkComponent.class)) { @@ -392,19 +363,14 @@ private EntityRef createBlockEntity(Vector3ic blockPosition, Block block) { blockEntity = builder.build(); } - blockEntityLookup.put(JomlUtil.from(blockPosition), blockEntity); + blockEntityLookup.put(new Vector3i(blockPosition), blockEntity); return blockEntity; } - @Override - public EntityRef getExistingEntityAt(Vector3i blockPosition) { - return getExistingEntityAt(JomlUtil.from(blockPosition)); - } - @Override public EntityRef getExistingEntityAt(Vector3ic blockPosition) { if (GameThread.isCurrentThread()) { - EntityRef result = blockRegionLookup.get((org.joml.Vector3i) blockPosition); + EntityRef result = blockRegionLookup.get(blockPosition); if (result == null) { return getExistingBlockEntityAt(blockPosition); } @@ -414,11 +380,6 @@ public EntityRef getExistingEntityAt(Vector3ic blockPosition) { return EntityRef.NULL; } - @Override - public EntityRef getEntityAt(Vector3i blockPosition) { - return getEntityAt(JomlUtil.from(blockPosition)); - } - @Override public EntityRef getEntityAt(Vector3ic blockPosition) { if (GameThread.isCurrentThread()) { @@ -432,15 +393,11 @@ public EntityRef getEntityAt(Vector3ic blockPosition) { return EntityRef.NULL; } - @Override - public boolean hasPermanentBlockEntity(Vector3i blockPos) { - return hasPermanentBlockEntity(JomlUtil.from(blockPos)); - } @Override public boolean hasPermanentBlockEntity(Vector3ic blockPos) { if (GameThread.isCurrentThread()) { - EntityRef blockEntity = blockEntityLookup.get(JomlUtil.from(blockPos)); + EntityRef blockEntity = blockEntityLookup.get(blockPos); return blockEntity != null && !temporaryBlockEntities.contains(blockEntity); } logger.error("Attempted check whether a block entity is permanent, off thread"); @@ -450,7 +407,7 @@ public boolean hasPermanentBlockEntity(Vector3ic blockPos) { @ReceiveEvent(components = {BlockComponent.class}) public void onActivateBlock(OnActivatedComponent event, EntityRef entity) { BlockComponent block = entity.getComponent(BlockComponent.class); - EntityRef oldEntity = blockEntityLookup.put(new Vector3i(block.position), entity); + EntityRef oldEntity = blockEntityLookup.put(block.getPosition(new Vector3i()), entity); // If this is a client, then an existing block entity may exist. Destroy it. if (oldEntity != null && !Objects.equal(oldEntity, entity)) { oldEntity.destroy(); @@ -460,8 +417,8 @@ public void onActivateBlock(OnActivatedComponent event, EntityRef entity) { @ReceiveEvent(components = {BlockComponent.class}) public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) { BlockComponent block = entity.getComponent(BlockComponent.class); - if (blockEntityLookup.get(block.position) == entity) { - blockEntityLookup.remove(block.position); + if (blockEntityLookup.get(block.getPosition(new Vector3i())) == entity) { + blockEntityLookup.remove(block.getPosition(new Vector3i())); } } @@ -469,28 +426,28 @@ public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) public void onBlockRegionActivated(OnActivatedComponent event, EntityRef entity) { BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (org.joml.Vector3ic pos : regionComp.region) { - blockRegionLookup.put(new org.joml.Vector3i(pos), entity); + for (Vector3ic pos : regionComp.region) { + blockRegionLookup.put(new Vector3i(pos), entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionChanged(OnChangedComponent event, EntityRef entity) { BlockRegion oldRegion = blockRegions.get(entity); - for (org.joml.Vector3ic pos : oldRegion) { + for (Vector3ic pos : oldRegion) { blockRegionLookup.remove(pos); } BlockRegionComponent regionComp = entity.getComponent(BlockRegionComponent.class); blockRegions.put(entity, regionComp.region); - for (org.joml.Vector3ic pos : regionComp.region) { - blockRegionLookup.put(new org.joml.Vector3i(pos), entity); + for (Vector3ic pos : regionComp.region) { + blockRegionLookup.put(new Vector3i(pos), entity); } } @ReceiveEvent(components = {BlockRegionComponent.class}) public void onBlockRegionDeactivated(BeforeDeactivateComponent event, EntityRef entity) { BlockRegion oldRegion = blockRegions.get(entity); - for (org.joml.Vector3ic pos : oldRegion) { + for (Vector3ic pos : oldRegion) { blockRegionLookup.remove(pos); } blockRegions.remove(entity); From 1177e4c021390e04809954984abbf9a91bf40bd5 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 6 Feb 2021 07:09:02 -0800 Subject: [PATCH 210/259] test(JOML): migrate and simplify PojoPrefabManagerTest (#4458) --- .../entitySystem/PojoPrefabManagerTest.java | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java b/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java index 7e7968c2ec0..4b783745926 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/PojoPrefabManagerTest.java @@ -4,26 +4,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.reflections.Reflections; -import org.terasology.assets.AssetFactory; import org.terasology.assets.ResourceUrn; import org.terasology.assets.management.AssetManager; import org.terasology.assets.module.ModuleAwareAssetTypeManager; import org.terasology.context.internal.ContextImpl; import org.terasology.engine.module.ModuleManager; -import org.terasology.entitySystem.metadata.ComponentLibrary; -import org.terasology.entitySystem.metadata.EntitySystemLibrary; import org.terasology.entitySystem.prefab.Prefab; import org.terasology.entitySystem.prefab.PrefabData; import org.terasology.entitySystem.prefab.internal.PojoPrefab; import org.terasology.entitySystem.prefab.internal.PojoPrefabManager; import org.terasology.entitySystem.stubs.StringComponent; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector3f; -import org.terasology.persistence.typeHandling.TypeHandlerLibrary; -import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyQuat4fTypeHandler; -import org.terasology.persistence.typeHandling.mathTypes.legacy.LegacyVector3fTypeHandler; import org.terasology.registry.CoreRegistry; import org.terasology.testUtil.ModuleManagerFactory; import org.terasology.utilities.Assets; @@ -37,8 +27,6 @@ public class PojoPrefabManagerTest { public static final String PREFAB_NAME = "unittest:myprefab"; - private EntitySystemLibrary entitySystemLibrary; - private ComponentLibrary componentLibrary; private PojoPrefabManager prefabManager; @BeforeEach @@ -47,18 +35,8 @@ public void setup() throws Exception { CoreRegistry.setContext(context); ModuleManager moduleManager = ModuleManagerFactory.create(); - Reflections reflections = new Reflections(getClass().getClassLoader()); - TypeHandlerLibrary lib = new TypeHandlerLibraryImpl(reflections); - - lib.addTypeHandler(Vector3f.class, new LegacyVector3fTypeHandler()); - lib.addTypeHandler(Quat4f.class, new LegacyQuat4fTypeHandler()); - - entitySystemLibrary = new EntitySystemLibrary(context, lib); - componentLibrary = entitySystemLibrary.getComponentLibrary(); - ModuleAwareAssetTypeManager assetTypeManager = new ModuleAwareAssetTypeManager(); - assetTypeManager.registerCoreAssetType(Prefab.class, - (AssetFactory) PojoPrefab::new, "prefabs"); + assetTypeManager.registerCoreAssetType(Prefab.class, PojoPrefab::new, "prefabs"); assetTypeManager.switchEnvironment(moduleManager.getEnvironment()); context.put(AssetManager.class, assetTypeManager.getAssetManager()); @@ -75,7 +53,7 @@ public void testRetrieveNonExistentPrefab() { public void testRetrievePrefab() { PrefabData data = new PrefabData(); data.addComponent(new StringComponent("Test")); - Prefab prefab = Assets.generateAsset(new ResourceUrn(PREFAB_NAME), data, Prefab.class); + Assets.generateAsset(new ResourceUrn(PREFAB_NAME), data, Prefab.class); Prefab ref = prefabManager.getPrefab(PREFAB_NAME); assertNotNull(ref); assertEquals(PREFAB_NAME, ref.getName()); From da677e65fc4fa42cc31a4dab9d788ad0f1800dc8 Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sat, 6 Feb 2021 19:02:00 +0100 Subject: [PATCH 211/259] feat(JOML)!: migrate `BlockComponent` (#4470) --- .../network/internal/NetClient.java | 7 +- .../network/internal/ServerImpl.java | 2 +- .../NetEntityRefTypeHandler.java | 5 +- .../world/block/BlockComponent.java | 85 ++++--------------- .../world/block/entity/BlockCommands.java | 2 +- .../NeighbourBlockFamilyUpdateSystem.java | 8 +- .../structure/SideBlockSupportRequired.java | 2 +- .../internal/EntityAwareWorldProvider.java | 11 +-- 8 files changed, 36 insertions(+), 86 deletions(-) diff --git a/engine/src/main/java/org/terasology/network/internal/NetClient.java b/engine/src/main/java/org/terasology/network/internal/NetClient.java index c531d0d7e5a..8031c8d3fc7 100644 --- a/engine/src/main/java/org/terasology/network/internal/NetClient.java +++ b/engine/src/main/java/org/terasology/network/internal/NetClient.java @@ -55,6 +55,7 @@ import org.terasology.world.block.BlockComponent; import org.terasology.world.block.family.BlockFamily; import org.terasology.world.chunks.Chunk; +import org.terasology.world.chunks.Chunks; import java.util.Arrays; import java.util.Iterator; @@ -335,9 +336,9 @@ public void send(Event event, EntityRef target) { try { BlockComponent blockComp = target.getComponent(BlockComponent.class); if (blockComp != null) { - if (relevantChunks.contains(ChunkMath.calcChunkPos(JomlUtil.from(blockComp.position), new Vector3i()))) { + if (relevantChunks.contains(Chunks.toChunkPos(blockComp.getPosition(), new Vector3i()))) { queuedOutgoingEvents.add(NetData.EventMessage.newBuilder() - .setTargetBlockPos(NetMessageUtil.convert(blockComp.position)) + .setTargetBlockPos(NetMessageUtil.convert(blockComp.getPosition())) .setEvent(eventSerializer.serialize(event)).build()); } } else { @@ -493,7 +494,7 @@ private void sendInitialEntities(NetData.NetMessage.Builder message) { NetData.CreateEntityMessage.Builder createMessage = NetData.CreateEntityMessage.newBuilder().setEntity(entityData); BlockComponent blockComponent = entity.getComponent(BlockComponent.class); if (blockComponent != null) { - createMessage.setBlockPos(NetMessageUtil.convert(blockComponent.position)); + createMessage.setBlockPos(NetMessageUtil.convert(blockComponent.getPosition())); } message.addCreateEntity(createMessage); } diff --git a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java index d89919093e4..ec793882451 100644 --- a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java +++ b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java @@ -367,7 +367,7 @@ private void updateEntity(NetData.UpdateEntityMessage updateEntity) { entitySerializer.deserializeOnto(currentEntity, updateEntity.getEntity()); BlockComponent blockComponent = currentEntity.getComponent(BlockComponent.class); if (blockComponent != null && !blockEntityBefore) { - if (!blockEntityRegistry.getExistingBlockEntityAt(blockComponent.getPosition(new Vector3i())).equals(currentEntity)) { + if (!blockEntityRegistry.getExistingBlockEntityAt(blockComponent.getPosition()).equals(currentEntity)) { logger.error("Failed to associated new block entity"); } } diff --git a/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java b/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java index 54afa67227f..4f8c6ceb228 100644 --- a/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java +++ b/engine/src/main/java/org/terasology/network/serialization/NetEntityRefTypeHandler.java @@ -17,6 +17,7 @@ package org.terasology.network.serialization; import gnu.trove.list.TIntList; +import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.JomlUtil; import org.terasology.math.geom.Vector3i; @@ -49,8 +50,8 @@ public NetEntityRefTypeHandler(NetworkSystemImpl networkSystem, BlockEntityRegis public PersistedData serializeNonNull(EntityRef value, PersistedDataSerializer serializer) { BlockComponent blockComponent = value.getComponent(BlockComponent.class); if (blockComponent != null) { - Vector3i pos = blockComponent.position; - return serializer.serialize(pos.x, pos.y, pos.z); + Vector3ic pos = blockComponent.getPosition(); + return serializer.serialize(pos.x(), pos.y(), pos.z()); } NetworkComponent netComponent = value.getComponent(NetworkComponent.class); if (netComponent != null) { diff --git a/engine/src/main/java/org/terasology/world/block/BlockComponent.java b/engine/src/main/java/org/terasology/world/block/BlockComponent.java index 4ddbb238a22..1bec685e7c2 100644 --- a/engine/src/main/java/org/terasology/world/block/BlockComponent.java +++ b/engine/src/main/java/org/terasology/world/block/BlockComponent.java @@ -1,23 +1,10 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 package org.terasology.world.block; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.terasology.entitySystem.Component; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.network.Replicate; /** @@ -25,80 +12,40 @@ */ public final class BlockComponent implements Component { @Replicate - public Vector3i position = new Vector3i(); + Vector3i position = new Vector3i(); @Replicate public Block block; public BlockComponent() { } - /** - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #BlockComponent(Block, org.joml.Vector3ic)}. - */ - @Deprecated - public BlockComponent(Block block, Vector3i pos) { - this.block = block; - this.position.set(pos); - } - public BlockComponent(Block block, org.joml.Vector3ic pos) { + public BlockComponent(Block block, Vector3ic pos) { this.block = block; - this.position.set(JomlUtil.from(pos)); + this.position.set(pos); } /** - * @deprecated Deprecated on 21/Sep/2018, because it is error prone (no defensive copy) and needlessly verbose. - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #getPosition(org.joml.Vector3i)}. + * Get an immutable view on the current position. + * + * Note: the vector may change when the position on this component is updated. If the position information is to be + * stored you should use {@link #getPosition(Vector3i)} instead. */ - @Deprecated - public Vector3i getPosition() { + public Vector3ic getPosition() { return position; } - /** - * @deprecated Deprecated on 21/Sep/2018, because it is needlessly verbose. - * @deprecated This is scheduled for removal in an upcoming version method will be replaced with JOML implementation - * {@link #setPosition(org.joml.Vector3i)}. - */ - @Deprecated - public void setPosition(Vector3i pos) { - position.set(pos); - } - - /** - * @deprecated Deprecated on 21/Sep/2018, because it is error prone (no defensive copy) and needlessly verbose. - */ - @Deprecated - public void setBlock(Block block) { - this.block = block; - } - - /** - * @deprecated Deprecated on 21/Sep/2018, because it is error prone (no defensive copy) and needlessly verbose. - */ - @Deprecated - public Block getBlock() { - return block; - } - /** * get the position * * @param dest will hold the result * @return dest */ - public org.joml.Vector3i getPosition(org.joml.Vector3i dest) { - dest.set(JomlUtil.from(position)); + public Vector3i getPosition(Vector3i dest) { + dest.set(position); return dest; } - /** - * set the position of the {@link BlockComponent} - * - * @param pos position to set - */ - public void setPosition(org.joml.Vector3i pos) { - position.set(JomlUtil.from(pos)); + public void setPosition(Vector3ic pos) { + position.set(pos); } } diff --git a/engine/src/main/java/org/terasology/world/block/entity/BlockCommands.java b/engine/src/main/java/org/terasology/world/block/entity/BlockCommands.java index d5001f174d0..84efd8db7ed 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/BlockCommands.java +++ b/engine/src/main/java/org/terasology/world/block/entity/BlockCommands.java @@ -212,7 +212,7 @@ public void replaceBlock( if (def.isPresent()) { BlockFamily blockFamily = blockManager.getBlockFamily(uri); Block block = blockManager.getBlock(blockFamily.getURI()); - world.setBlock(targetLocation.position, block); + world.setBlock(targetLocation.getPosition(), block); } else if (matchingUris.size() > 1) { StringBuilder builder = new StringBuilder(); builder.append("Non-unique shape name, possible matches: "); diff --git a/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java b/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java index d2947f8b7e5..9563fcb36be 100644 --- a/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java +++ b/engine/src/main/java/org/terasology/world/block/entity/neighbourUpdate/NeighbourBlockFamilyUpdateSystem.java @@ -17,6 +17,7 @@ import com.google.common.collect.Sets; import org.joml.Vector3i; +import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; @@ -81,7 +82,7 @@ public void onBlockPlaced(OnBlockItemPlaced event, EntityRef entity) { return; } - processUpdateForBlockLocation(JomlUtil.from(blockComponent.position)); + processUpdateForBlockLocation(blockComponent.getPosition()); } private void notifyNeighboursOfChangedBlocks() { @@ -108,10 +109,9 @@ public void blockUpdate(OnChangedBlock event, EntityRef blockEntity) { } } - private void processUpdateForBlockLocation(Vector3i blockLocation) { + private void processUpdateForBlockLocation(Vector3ic blockLocation) { for (Side side : Side.getAllSides()) { - Vector3i neighborLocation = new Vector3i(blockLocation); - neighborLocation.add(side.direction()); + Vector3i neighborLocation = blockLocation.add(side.direction(), new Vector3i()); if (worldProvider.isBlockRelevant(neighborLocation)) { Block neighborBlock = worldProvider.getBlock(neighborLocation); final BlockFamily blockFamily = neighborBlock.getBlockFamily(); diff --git a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java index c0e32758cc4..fd79f25d3de 100644 --- a/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java +++ b/engine/src/main/java/org/terasology/world/block/structure/SideBlockSupportRequired.java @@ -65,7 +65,7 @@ public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { @ReceiveEvent public void checkForSupport(DelayedActionTriggeredEvent event, EntityRef entity, BlockComponent block, SideBlockSupportRequiredComponent supportRequired) { if (event.getActionId().equals(SUPPORT_CHECK_ACTION_ID)) { - if (!isSufficientlySupported(JomlUtil.from(block.position), null, Collections.emptyMap(), supportRequired)) { + if (!isSufficientlySupported(block.getPosition(), null, Collections.emptyMap(), supportRequired)) { PrefabManager prefabManager = CoreRegistry.get(PrefabManager.class); entity.send(new DestroyEvent(entity, EntityRef.NULL, prefabManager.getPrefab("engine:supportRemovedDamage"))); } diff --git a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java index 2fe859da2be..1629da18a51 100644 --- a/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java +++ b/engine/src/main/java/org/terasology/world/internal/EntityAwareWorldProvider.java @@ -286,7 +286,7 @@ private void updateBlockEntityComponents(EntityRef blockEntity, Block oldType, B Optional oldPrefab = oldType.getPrefab(); EntityBuilder oldEntityBuilder = entityManager.newBuilder(oldPrefab.orElse(null)); - oldEntityBuilder.addComponent(new BlockComponent(oldType, blockComponent.position)); + oldEntityBuilder.addComponent(new BlockComponent(oldType, blockComponent.getPosition())); BeforeEntityCreated oldEntityEvent = new BeforeEntityCreated(oldPrefab.orElse(null), oldEntityBuilder.iterateComponents()); blockEntity.send(oldEntityEvent); for (Component comp : oldEntityEvent.getResultComponents()) { @@ -295,7 +295,7 @@ private void updateBlockEntityComponents(EntityRef blockEntity, Block oldType, B Optional newPrefab = type.getPrefab(); EntityBuilder newEntityBuilder = entityManager.newBuilder(newPrefab.orElse(null)); - newEntityBuilder.addComponent(new BlockComponent(type, blockComponent.position)); + newEntityBuilder.addComponent(new BlockComponent(type, blockComponent.getPosition())); BeforeEntityCreated newEntityEvent = new BeforeEntityCreated(newPrefab.orElse(null), newEntityBuilder.iterateComponents()); blockEntity.send(newEntityEvent); for (Component comp : newEntityEvent.getResultComponents()) { @@ -417,8 +417,8 @@ public void onActivateBlock(OnActivatedComponent event, EntityRef entity) { @ReceiveEvent(components = {BlockComponent.class}) public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) { BlockComponent block = entity.getComponent(BlockComponent.class); - if (blockEntityLookup.get(block.getPosition(new Vector3i())) == entity) { - blockEntityLookup.remove(block.getPosition(new Vector3i())); + if (blockEntityLookup.get(block.getPosition()) == entity) { + blockEntityLookup.remove(block.getPosition()); } } @@ -517,7 +517,8 @@ public void onEntityComponentRemoved(EntityRef entity, Class Date: Sat, 6 Feb 2021 14:21:58 -0800 Subject: [PATCH 212/259] feat(JOML): migrate ChunkView (#4469) Co-authored-by: Tobias Nett --- .../LocalChunkProviderTest.java | 39 ++-- .../BetweenChunkPropagationTest.java | 44 ++--- .../renderer/HeadlessWorldRenderer.java | 7 +- .../console/commands/ServerCommands.java | 2 +- .../network/internal/ServerImpl.java | 2 +- .../engine/VoxelLiquidWorldSystem.java | 18 +- .../physics/engine/VoxelWorldSystem.java | 18 +- .../rendering/world/RenderableWorldImpl.java | 6 +- .../world/chunks/ChunkProvider.java | 29 +-- .../LocalChunkProvider.java | 185 ++++++++---------- .../localChunkProvider/RelevanceSystem.java | 4 +- .../RemoteChunkProvider.java | 93 ++++----- .../world/internal/WorldProviderCoreImpl.java | 6 +- .../world/propagation/LocalChunkView.java | 11 +- 14 files changed, 203 insertions(+), 261 deletions(-) diff --git a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java index d1a06fa3a93..1a4c49c984e 100644 --- a/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -3,6 +3,8 @@ package org.terasology.world.chunks.localChunkProvider; import com.google.common.collect.Maps; +import org.joml.Vector3i; +import org.joml.Vector3ic; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -16,7 +18,6 @@ import org.terasology.fixtures.TestStorageManager; import org.terasology.fixtures.TestWorldGenerator; import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.world.BlockEntityRegistry; import org.terasology.world.block.BeforeDeactivateBlocks; import org.terasology.world.block.Block; @@ -54,7 +55,7 @@ class LocalChunkProviderTest { private ExtraBlockDataManager extraDataManager; private BlockEntityRegistry blockEntityRegistry; private EntityRef worldEntity; - private Map chunkCache; + private Map chunkCache; private Block blockAtBlockManager; private TestStorageManager storageManager; private TestWorldGenerator generator; @@ -89,21 +90,21 @@ public void tearDown() { chunkProvider.shutdown(); } - private Future requestCreatingOrLoadingArea(Vector3i chunkPosition, int radius) { + private Future requestCreatingOrLoadingArea(Vector3ic chunkPosition, int radius) { Future chunkFuture = chunkProvider.createOrLoadChunk(chunkPosition); BlockRegion extentsRegion = new BlockRegion( - chunkPosition.x - radius, chunkPosition.y - radius, chunkPosition.z - radius, - chunkPosition.x + radius, chunkPosition.y + radius, chunkPosition.z + radius); + chunkPosition.x() - radius, chunkPosition.y() - radius, chunkPosition.z() - radius, + chunkPosition.x() + radius, chunkPosition.y() + radius, chunkPosition.z() + radius); extentsRegion.iterator().forEachRemaining(pos -> { - if (!pos.equals(JomlUtil.from(chunkPosition))) { // remove center. we takes future for it already. - chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); + if (!pos.equals(chunkPosition)) { // remove center. we takes future for it already. + chunkProvider.createOrLoadChunk(pos); } }); return chunkFuture; } - private Future requestCreatingOrLoadingArea(Vector3i chunkPosition) { + private Future requestCreatingOrLoadingArea(Vector3ic chunkPosition) { return requestCreatingOrLoadingArea(chunkPosition, 1); } @@ -121,14 +122,14 @@ void testGenerateSingleChunk() throws InterruptedException, ExecutionException, Assertions.assertTrue(mustBeOnGeneratedEvent instanceof OnChunkGenerated, "First world event must be OnChunkGenerated"); Assertions.assertEquals(((OnChunkGenerated) mustBeOnGeneratedEvent).getChunkPos(), - JomlUtil.from(chunkPosition), + chunkPosition, "Chunk position at event not expected"); }, () -> { Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(1); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(JomlUtil.from(chunkPosition), + Assertions.assertEquals(chunkPosition, ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); }); @@ -150,14 +151,14 @@ void testGenerateSingleChunkWithBlockLifeCycle() throws InterruptedException, Ex Assertions.assertTrue(mustBeOnGeneratedEvent instanceof OnChunkGenerated, "First world event must be OnChunkGenerated"); Assertions.assertEquals(((OnChunkGenerated) mustBeOnGeneratedEvent).getChunkPos(), - JomlUtil.from(chunkPosition), + chunkPosition, "Chunk position at event not expected"); }, () -> { Event mustBeOnLoadedEvent = worldEventCaptor.getAllValues().get(1); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(JomlUtil.from(chunkPosition), + Assertions.assertEquals(chunkPosition, ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); }); @@ -177,14 +178,14 @@ void testGenerateSingleChunkWithBlockLifeCycle() throws InterruptedException, Ex @Test void testLoadSingleChunk() throws InterruptedException, ExecutionException, TimeoutException { Vector3i chunkPosition = new Vector3i(0, 0, 0); - Chunk chunk = new ChunkImpl(chunkPosition, blockManager, extraDataManager); + Chunk chunk = new ChunkImpl(JomlUtil.from(chunkPosition), blockManager, extraDataManager); generator.createChunk(chunk, null); storageManager.add(chunk); requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); chunkProvider.update(); - Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(JomlUtil.from(chunkPosition))).isEntityRestored(), + Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), "Entities must be restored by loading"); final ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(Event.class); @@ -192,7 +193,7 @@ void testLoadSingleChunk() throws InterruptedException, ExecutionException, Time Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(0); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(JomlUtil.from(chunkPosition), + Assertions.assertEquals(chunkPosition, ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); } @@ -200,7 +201,7 @@ void testLoadSingleChunk() throws InterruptedException, ExecutionException, Time @Test void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, ExecutionException, TimeoutException { Vector3i chunkPosition = new Vector3i(0, 0, 0); - Chunk chunk = new ChunkImpl(chunkPosition, blockManager, extraDataManager); + Chunk chunk = new ChunkImpl(JomlUtil.from(chunkPosition), blockManager, extraDataManager); generator.createChunk(chunk, null); storageManager.add(chunk); blockAtBlockManager.setLifecycleEventsRequired(true); @@ -209,7 +210,7 @@ void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, Execut requestCreatingOrLoadingArea(chunkPosition).get(WAIT_CHUNK_IS_READY_IN_SECONDS, TimeUnit.SECONDS); chunkProvider.update(); - Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(JomlUtil.from(chunkPosition))).isEntityRestored(), + Assertions.assertTrue(((TestChunkStore) storageManager.loadChunkStore(chunkPosition)).isEntityRestored(), "Entities must be restored by loading"); @@ -218,7 +219,7 @@ void testLoadSingleChunkWithBlockLifecycle() throws InterruptedException, Execut Event mustBeOnLoadedEvent = eventArgumentCaptor.getAllValues().get(0); Assertions.assertTrue(mustBeOnLoadedEvent instanceof OnChunkLoaded, "Second world event must be OnChunkLoaded"); - Assertions.assertEquals(JomlUtil.from(chunkPosition), + Assertions.assertEquals(chunkPosition, ((OnChunkLoaded) mustBeOnLoadedEvent).getChunkPos(), "Chunk position at event not expected"); @@ -278,7 +279,7 @@ void testUnloadChunkAndDeactivationBlock() throws InterruptedException, TimeoutE Assertions.assertTrue(beforeChunkUnload.isPresent(), "World events must have BeforeChunkUnload event when chunk was unload"); - Assertions.assertEquals(JomlUtil.from(chunkPosition), + Assertions.assertEquals(chunkPosition, beforeChunkUnload.get().getChunkPos(), "Chunk position at event not expected"); diff --git a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java index 670d2a1836e..3e8c8cdc8d5 100644 --- a/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java +++ b/engine-tests/src/test/java/org/terasology/world/propagation/BetweenChunkPropagationTest.java @@ -16,6 +16,7 @@ package org.terasology.world.propagation; import com.google.common.collect.Maps; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,9 +25,7 @@ import org.terasology.assets.management.AssetManager; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.math.Side; -import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; @@ -101,8 +100,8 @@ public void setup() throws Exception { @Test public void testBetweenChunksSimple() { - Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, extraDataManager); - Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, extraDataManager); + Chunk topChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 1, 0)), blockManager, extraDataManager); + Chunk bottomChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 0, 0)), blockManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); @@ -123,8 +122,8 @@ public void testBetweenChunksSimple() { @Test public void testBetweenChunksSimpleSunlightRegenOnly() { - Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, extraDataManager); - Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, extraDataManager); + Chunk topChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 1, 0)), blockManager, extraDataManager); + Chunk bottomChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 0, 0)), blockManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); @@ -143,8 +142,8 @@ public void testBetweenChunksSimpleSunlightRegenOnly() { @Test public void testBetweenChunksWithOverhang() { - Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, extraDataManager); - Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, extraDataManager); + Chunk topChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 1, 0)), blockManager, extraDataManager); + Chunk bottomChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 0, 0)), blockManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); @@ -171,8 +170,8 @@ public void testBetweenChunksWithOverhang() { @Test public void testPropagateSunlightAppearingMidChunk() { - Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, extraDataManager); - Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, extraDataManager); + Chunk topChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 1, 0)), blockManager, extraDataManager); + Chunk bottomChunk = new ChunkImpl(JomlUtil.from(new Vector3i(0, 0, 0)), blockManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); @@ -199,35 +198,35 @@ public void testPropagateSunlightAppearingMidChunk() { } private static class SelectChunkProvider implements ChunkProvider { - private Map chunks = Maps.newHashMap(); + private Map chunks = Maps.newHashMap(); SelectChunkProvider(Chunk... chunks) { for (Chunk chunk : chunks) { - this.chunks.put(chunk.getPosition(), chunk); + this.chunks.put(chunk.getPosition(new Vector3i()), chunk); } } public void addChunk(Chunk chunk) { - chunks.put(chunk.getPosition(), chunk); + chunks.put(chunk.getPosition(new Vector3i()), chunk); } @Override - public ChunkViewCore getLocalView(Vector3i centerChunkPos) { + public ChunkViewCore getLocalView(Vector3ic centerChunkPos) { return null; } @Override - public ChunkViewCore getSubviewAroundBlock(Vector3i blockPos, int extent) { + public ChunkViewCore getSubviewAroundBlock(Vector3ic blockPos, int extent) { return null; } @Override - public ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos) { + public ChunkViewCore getSubviewAroundChunk(Vector3ic chunkPos) { return null; } @Override - public boolean reloadChunk(Vector3i pos) { + public boolean reloadChunk(Vector3ic pos) { return false; } @@ -246,11 +245,6 @@ public void update() { // do nothing } - @Override - public boolean isChunkReady(Vector3i pos) { - return false; - } - @Override public boolean isChunkReady(Vector3ic pos) { return false; @@ -261,14 +255,10 @@ public Chunk getChunk(int x, int y, int z) { return getChunk(new Vector3i(x, y, z)); } - @Override - public Chunk getChunk(Vector3i chunkPos) { - return chunks.get(chunkPos); - } @Override public Chunk getChunk(Vector3ic chunkPos) { - return chunks.get(JomlUtil.from(chunkPos)); + return chunks.get(chunkPos); } @Override diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java index 97b6d232a2b..48945a5fba7 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java @@ -20,6 +20,7 @@ import org.terasology.config.Config; import org.terasology.context.Context; import org.terasology.logic.players.LocalPlayerSystem; +import org.terasology.math.JomlUtil; import org.terasology.math.Region3i; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; @@ -211,7 +212,7 @@ public boolean updateChunksInProximity(boolean force) { // just add all visible chunks chunksInProximity.clear(); for (Vector3i chunkPosition : viewRegion) { - RenderableChunk c = chunkProvider.getChunk(chunkPosition); + RenderableChunk c = chunkProvider.getChunk(JomlUtil.from(chunkPosition)); if (c != null && worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())) != null) { chunksInProximity.add(c); } else { @@ -225,7 +226,7 @@ public boolean updateChunksInProximity(boolean force) { // remove while (chunksForRemove.hasNext()) { Vector3i r = chunksForRemove.next(); - RenderableChunk c = chunkProvider.getChunk(r); + RenderableChunk c = chunkProvider.getChunk(JomlUtil.from(r)); if (c != null) { chunksInProximity.remove(c); c.disposeMesh(); @@ -234,7 +235,7 @@ public boolean updateChunksInProximity(boolean force) { // add for (Vector3i chunkPosition : viewRegion) { - RenderableChunk c = chunkProvider.getChunk(chunkPosition); + RenderableChunk c = chunkProvider.getChunk(JomlUtil.from(chunkPosition)); if (c != null && worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())) != null) { chunksInProximity.add(c); } else { diff --git a/engine/src/main/java/org/terasology/logic/console/commands/ServerCommands.java b/engine/src/main/java/org/terasology/logic/console/commands/ServerCommands.java index 4b54e4cc32b..ba4f5aca96a 100644 --- a/engine/src/main/java/org/terasology/logic/console/commands/ServerCommands.java +++ b/engine/src/main/java/org/terasology/logic/console/commands/ServerCommands.java @@ -15,6 +15,7 @@ */ package org.terasology.logic.console.commands; +import org.joml.Vector3i; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.config.Config; @@ -31,7 +32,6 @@ import org.terasology.logic.console.suggesters.UsernameSuggester; import org.terasology.logic.permission.PermissionManager; import org.terasology.logic.players.PlayerUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.network.Client; import org.terasology.network.ClientComponent; import org.terasology.network.ClientInfoComponent; diff --git a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java index ec793882451..876bec36c75 100644 --- a/engine/src/main/java/org/terasology/network/internal/ServerImpl.java +++ b/engine/src/main/java/org/terasology/network/internal/ServerImpl.java @@ -318,7 +318,7 @@ private void processExtraDataChanges(NetData.NetMessage message) { private void processInvalidatedChunks(NetData.NetMessage message) { for (NetData.InvalidateChunkMessage chunk : message.getInvalidateChunkList()) { Vector3i chunkPos = NetMessageUtil.convert(chunk.getPos()); - remoteWorldProvider.invalidateChunks(JomlUtil.from(chunkPos)); + remoteWorldProvider.invalidateChunks(chunkPos); awaitingChunkReadyBlockUpdates.removeAll(chunkPos); awaitingChunkReadyExtraDataUpdates.removeAll(chunkPos); } diff --git a/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java b/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java index 8a5d8f2032e..9c205615da4 100644 --- a/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java +++ b/engine/src/main/java/org/terasology/physics/engine/VoxelLiquidWorldSystem.java @@ -33,8 +33,6 @@ import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterSystem; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.physics.StandardCollisionGroup; import org.terasology.physics.bullet.BulletPhysics; import org.terasology.physics.bullet.shapes.BulletCollisionShape; @@ -45,8 +43,8 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.chunks.Chunk; -import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.event.BeforeChunkUnload; import org.terasology.world.chunks.event.OnChunkLoaded; @@ -83,8 +81,8 @@ public void initialise() { if (physics instanceof BulletPhysics) { btDiscreteDynamicsWorld discreteDynamicsWorld = ((BulletPhysics) physics).getDiscreteDynamicsWorld(); - wrapper = new VoxelCollisionAlgorithmWrapper(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, - ChunkConstants.SIZE_Z); + wrapper = new VoxelCollisionAlgorithmWrapper(Chunks.SIZE_X, Chunks.SIZE_Y, + Chunks.SIZE_Z); worldShape = new btVoxelShape(wrapper, new Vector3f(-AABB_SIZE, -AABB_SIZE, -AABB_SIZE), new Vector3f(AABB_SIZE, AABB_SIZE, AABB_SIZE)); @@ -144,13 +142,13 @@ public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldE @ReceiveEvent(components = WorldComponent.class) public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { Vector3ic chunkPos = chunkAvailable.getChunkPos(); - Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkPos)); + Chunk chunk = chunkProvider.getChunk(chunkPos); ByteBuffer buffer = - ByteBuffer.allocateDirect(2 * (ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z)); + ByteBuffer.allocateDirect(2 * (Chunks.SIZE_X * Chunks.SIZE_Y * Chunks.SIZE_Z)); buffer.order(ByteOrder.nativeOrder()); - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int y = 0; y < ChunkConstants.SIZE_Y; y++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int y = 0; y < Chunks.SIZE_Y; y++) { Block block = chunk.getBlock(x, y, z); tryRegister(block); buffer.putShort(block.getId()); diff --git a/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java b/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java index a6c0ad156f0..68efa667faf 100644 --- a/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java +++ b/engine/src/main/java/org/terasology/physics/engine/VoxelWorldSystem.java @@ -33,8 +33,6 @@ import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.systems.BaseComponentSystem; import org.terasology.entitySystem.systems.RegisterSystem; -import org.terasology.math.JomlUtil; -import org.terasology.math.geom.Vector3i; import org.terasology.physics.StandardCollisionGroup; import org.terasology.physics.bullet.BulletPhysics; import org.terasology.physics.bullet.shapes.BulletCollisionShape; @@ -45,8 +43,8 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import org.terasology.world.chunks.Chunk; -import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.event.BeforeChunkUnload; import org.terasology.world.chunks.event.OnChunkLoaded; @@ -82,8 +80,8 @@ public void initialise() { if (physics instanceof BulletPhysics) { btDiscreteDynamicsWorld discreteDynamicsWorld = ((BulletPhysics) physics).getDiscreteDynamicsWorld(); - wrapper = new VoxelCollisionAlgorithmWrapper(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, - ChunkConstants.SIZE_Z); + wrapper = new VoxelCollisionAlgorithmWrapper(Chunks.SIZE_X, Chunks.SIZE_Y, + Chunks.SIZE_Z); worldShape = new btVoxelShape(wrapper, new Vector3f(-AABB_SIZE, -AABB_SIZE, -AABB_SIZE), new Vector3f(AABB_SIZE, AABB_SIZE, AABB_SIZE)); @@ -143,13 +141,13 @@ public void onChunkUloaded(BeforeChunkUnload beforeChunkUnload, EntityRef worldE @ReceiveEvent(components = WorldComponent.class) public void onNewChunk(OnChunkLoaded chunkAvailable, EntityRef worldEntity) { Vector3ic chunkPos = chunkAvailable.getChunkPos(); - Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkPos)); + Chunk chunk = chunkProvider.getChunk(chunkPos); ByteBuffer buffer = - ByteBuffer.allocateDirect(2 * (ChunkConstants.SIZE_X * ChunkConstants.SIZE_Y * ChunkConstants.SIZE_Z)); + ByteBuffer.allocateDirect(2 * (Chunks.SIZE_X * Chunks.SIZE_Y * Chunks.SIZE_Z)); buffer.order(ByteOrder.nativeOrder()); - for (int z = 0; z < ChunkConstants.SIZE_Z; z++) { - for (int x = 0; x < ChunkConstants.SIZE_X; x++) { - for (int y = 0; y < ChunkConstants.SIZE_Y; y++) { + for (int z = 0; z < Chunks.SIZE_Z; z++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int y = 0; y < Chunks.SIZE_Y; y++) { Block block = chunk.getBlock(x, y, z); tryRegister(block); buffer.putShort(block.getId()); diff --git a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java index 1804017a4e2..fb990e84471 100644 --- a/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/RenderableWorldImpl.java @@ -117,7 +117,7 @@ class RenderableWorldImpl implements RenderableWorld { @Override public void onChunkLoaded(Vector3ic chunkCoordinates) { if (renderableRegion.contains(chunkCoordinates)) { - Chunk chunk = chunkProvider.getChunk(JomlUtil.from(chunkCoordinates)); + Chunk chunk = chunkProvider.getChunk(chunkCoordinates); if (chunk != null) { chunksInProximityOfCamera.add(chunk); Collections.sort(chunksInProximityOfCamera, new ChunkFrontToBackComparator()); @@ -168,7 +168,7 @@ public boolean pregenerateChunks() { ChunkMesh newMesh; ChunkView localView; for (Vector3ic chunkCoordinates : calculateRenderableRegion(renderingConfig.getViewDistance())) { - chunk = chunkProvider.getChunk(JomlUtil.from(chunkCoordinates)); + chunk = chunkProvider.getChunk(chunkCoordinates); if (chunk == null) { pregenerationIsComplete = false; } else if (chunk.isDirty()) { @@ -241,7 +241,7 @@ public boolean updateChunksInProximity(BlockRegion newRenderableRegion) { boolean chunksHaveBeenAdded = false; for (Vector3ic chunkPositionToAdd : newRenderableRegion) { if (!renderableRegion.contains(chunkPositionToAdd)) { - chunk = chunkProvider.getChunk(JomlUtil.from(chunkPositionToAdd)); + chunk = chunkProvider.getChunk(chunkPositionToAdd); if (chunk != null) { chunksInProximityOfCamera.add(chunk); chunksHaveBeenAdded = true; diff --git a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java index 16dfe8558a2..65cc32b5425 100644 --- a/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/ChunkProvider.java @@ -5,7 +5,6 @@ import org.joml.Vector3ic; import org.terasology.entitySystem.entity.EntityRef; -import org.terasology.math.geom.Vector3i; import org.terasology.world.internal.ChunkViewCore; import java.util.Collection; @@ -21,20 +20,20 @@ public interface ChunkProvider { * @param centerChunkPos * @return A chunk view centered on the given chunk, with all of the surrounding chunks included. */ - ChunkViewCore getLocalView(Vector3i centerChunkPos); + ChunkViewCore getLocalView(Vector3ic centerChunkPos); /** * @param blockPos * @param extent * @return A chunk view of the chunks around the given blockPos. */ - ChunkViewCore getSubviewAroundBlock(Vector3i blockPos, int extent); + ChunkViewCore getSubviewAroundBlock(Vector3ic blockPos, int extent); /** * @param chunkPos * @return A chunk view including the chunks around the given chunk */ - ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos); + ChunkViewCore getSubviewAroundChunk(Vector3ic chunkPos); /** * Sets the world entity, for the purpose of receiving chunk events. @@ -52,25 +51,20 @@ public interface ChunkProvider { * @param pos the chunk coordinates * @return whether this chunk was purged successfully or not */ - boolean reloadChunk(Vector3i pos); + boolean reloadChunk(Vector3ic pos); /** * Purges all chunks that are currently loaded and force their re-generation. */ void purgeWorld(); - /** - * @param pos - * @return Whether this chunk is available and ready for use - */ - boolean isChunkReady(Vector3i pos); - /** * @param pos * @return Whether this chunk is available and ready for use */ boolean isChunkReady(Vector3ic pos); + /** * Returns the chunk at the given position if possible. * @@ -80,17 +74,7 @@ public interface ChunkProvider { * @return The chunk, or null if the chunk is not ready */ Chunk getChunk(int x, int y, int z); - - /** - * Returns the chunk at the given position if possible. - * - * @param chunkPos The position of the chunk to obtain - * @return The chunk, or null if the chunk is not ready - * @deprecated use {@link #getChunk(org.joml.Vector3ic)} instead. TODO replace with joml. - */ - @Deprecated - Chunk getChunk(Vector3i chunkPos); - + /** * Returns the chunk at the given position if possible. * @@ -99,7 +83,6 @@ public interface ChunkProvider { */ Chunk getChunk(Vector3ic chunkPos); - /** * Disposes the chunk provider, cleaning up all chunks and other assets it is using */ diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java index e63095b4513..0dda8e387aa 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/LocalChunkProvider.java @@ -10,6 +10,7 @@ import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.TShortObjectMap; import gnu.trove.map.hash.TShortObjectHashMap; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,9 +21,7 @@ import org.terasology.entitySystem.prefab.Prefab; import org.terasology.math.ChunkMath; import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.monitoring.chunk.ChunkMonitor; import org.terasology.persistence.ChunkStore; @@ -33,12 +32,14 @@ import org.terasology.world.block.Block; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; +import org.terasology.world.block.BlockRegionc; import org.terasology.world.block.OnActivatedBlocks; import org.terasology.world.block.OnAddedBlocks; import org.terasology.world.chunks.Chunk; import org.terasology.world.chunks.ChunkBlockIterator; import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; +import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.ManagedChunk; import org.terasology.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.world.chunks.event.BeforeChunkUnload; @@ -95,9 +96,9 @@ public class LocalChunkProvider implements ChunkProvider { private final EntityManager entityManager; private final BlockingQueue readyChunks = Queues.newLinkedBlockingQueue(); private final BlockingQueue> deactivateBlocksQueue = Queues.newLinkedBlockingQueue(); - private final Map chunkCache; + private final Map chunkCache; - private final Map> generateQueuedEntities = new ConcurrentHashMap<>(); + private final Map> generateQueuedEntities = new ConcurrentHashMap<>(); private final StorageManager storageManager; private final WorldGenerator generator; @@ -112,7 +113,7 @@ public class LocalChunkProvider implements ChunkProvider { public LocalChunkProvider(StorageManager storageManager, EntityManager entityManager, WorldGenerator generator, BlockManager blockManager, ExtraBlockDataManager extraDataManager, - Map chunkCache) { + Map chunkCache) { this.storageManager = storageManager; this.entityManager = entityManager; this.generator = generator; @@ -124,22 +125,23 @@ public LocalChunkProvider(StorageManager storageManager, EntityManager entityMan } - protected Future createOrLoadChunk(Vector3i chunkPos) { + protected Future createOrLoadChunk(Vector3ic chunkPos) { + Vector3i pos = new Vector3i(chunkPos); return loadingPipeline.invokeGeneratorTask( - JomlUtil.from(chunkPos), - () -> { - ChunkStore chunkStore = storageManager.loadChunkStore(JomlUtil.from(chunkPos)); - Chunk chunk; - EntityBufferImpl buffer = new EntityBufferImpl(); - if (chunkStore == null) { - chunk = new ChunkImpl(chunkPos, blockManager, extraDataManager); - generator.createChunk(chunk, buffer); - generateQueuedEntities.put(chunk.getPosition(new org.joml.Vector3i()), buffer.getAll()); - } else { - chunk = chunkStore.getChunk(); - } - return chunk; - }); + pos, + () -> { + ChunkStore chunkStore = storageManager.loadChunkStore(pos); + Chunk chunk; + EntityBufferImpl buffer = new EntityBufferImpl(); + if (chunkStore == null) { + chunk = new ChunkImpl(JomlUtil.from(pos), blockManager, extraDataManager); + generator.createChunk(chunk, buffer); + generateQueuedEntities.put(chunk.getPosition(new Vector3i()), buffer.getAll()); + } else { + chunk = chunkStore.getChunk(); + } + return chunk; + }); } public void setBlockEntityRegistry(BlockEntityRegistry value) { @@ -147,38 +149,37 @@ public void setBlockEntityRegistry(BlockEntityRegistry value) { } @Override - public ChunkViewCore getLocalView(Vector3i centerChunkPos) { - Region3i region = Region3i.createFromCenterExtents(centerChunkPos, ChunkConstants.LOCAL_REGION_EXTENTS); + public ChunkViewCore getLocalView(Vector3ic centerChunkPos) { + BlockRegion region = new BlockRegion(centerChunkPos).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(centerChunkPos) != null) { - return createWorldView(region, Vector3i.one()); + return createWorldView(region, new Vector3i(1, 1, 1)); } return null; } @Override - public ChunkViewCore getSubviewAroundBlock(Vector3i blockPos, int extent) { - Region3i region = ChunkMath.getChunkRegionAroundWorldPos(blockPos, extent); - return createWorldView(region, new Vector3i(-region.min().x, -region.min().y, -region.min().z)); + public ChunkViewCore getSubviewAroundBlock(Vector3ic blockPos, int extent) { + BlockRegion region = Chunks.toChunkRegion(new BlockRegion(blockPos).expand(extent, extent, extent)); + return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } @Override - public ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos) { - Region3i region = Region3i.createFromCenterExtents(chunkPos, ChunkConstants.LOCAL_REGION_EXTENTS); + public ChunkViewCore getSubviewAroundChunk(Vector3ic chunkPos) { + BlockRegion region = new BlockRegion(chunkPos).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(chunkPos) != null) { - return createWorldView(region, new Vector3i(-region.min().x, -region.min().y, -region.min().z)); + return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } return null; } - private ChunkViewCore createWorldView(Region3i region, Vector3i offset) { - Chunk[] chunks = new Chunk[region.sizeX() * region.sizeY() * region.sizeZ()]; - for (Vector3i chunkPos : region) { + private ChunkViewCore createWorldView(BlockRegionc region, Vector3ic offset) { + Chunk[] chunks = new Chunk[region.volume()]; + for (Vector3ic chunkPos : region) { Chunk chunk = chunkCache.get(chunkPos); - chunkPos.sub(region.minX(), region.minY(), region.minZ()); - int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size()); + int index = (chunkPos.x() - region.minX()) + region.getSizeX() * ((chunkPos.z() - region.minZ()) + region.getSizeZ() * (chunkPos.y() - region.minY())); chunks[index] = chunk; } - return new ChunkViewCoreImpl(chunks, JomlUtil.from(region), JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); + return new ChunkViewCoreImpl(chunks, region, offset, blockManager.getBlock(BlockManager.AIR_ID)); } @Override @@ -188,14 +189,14 @@ public void setWorldEntity(EntityRef worldEntity) { private void processReadyChunk(final Chunk chunk) { - if (chunkCache.get(chunk.getPosition()) != null) { + if (chunkCache.get(chunk.getPosition(new Vector3i())) != null) { return; // TODO move it in pipeline; } - chunkCache.put(chunk.getPosition(), chunk); + chunkCache.put(chunk.getPosition(new Vector3i()), chunk); chunk.markReady(); //TODO, it is not clear if the activate/addedBlocks event logic is correct. //See https://github.com/MovingBlocks/Terasology/issues/3244 - ChunkStore store = this.storageManager.loadChunkStore(chunk.getPosition(new org.joml.Vector3i())); + ChunkStore store = this.storageManager.loadChunkStore(chunk.getPosition(new Vector3i())); TShortObjectMap mappings = createBatchBlockEventMappings(chunk); if (store != null) { store.restoreEntities(); @@ -222,7 +223,7 @@ private void processReadyChunk(final Chunk chunk) { PerformanceMonitor.endActivity(); } else { PerformanceMonitor.startActivity("Generating queued Entities"); - generateQueuedEntities.remove(chunk.getPosition(new org.joml.Vector3i())).forEach(this::generateQueuedEntities); + generateQueuedEntities.remove(chunk.getPosition(new Vector3i())).forEach(this::generateQueuedEntities); PerformanceMonitor.endActivity(); // send on activate @@ -237,9 +238,9 @@ private void processReadyChunk(final Chunk chunk) { PerformanceMonitor.endActivity(); - worldEntity.send(new OnChunkGenerated(chunk.getPosition(new org.joml.Vector3i()))); + worldEntity.send(new OnChunkGenerated(chunk.getPosition(new Vector3i()))); } - worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); + worldEntity.send(new OnChunkLoaded(chunk.getPosition(new Vector3i()))); } private void generateQueuedEntities(EntityStore store) { @@ -267,7 +268,7 @@ public void update() { private void deactivateBlocks() { List> deactivatedBlockSets = - Lists.newArrayListWithExpectedSize(deactivateBlocksQueue.size()); + Lists.newArrayListWithExpectedSize(deactivateBlocksQueue.size()); deactivateBlocksQueue.drainTo(deactivatedBlockSets); for (TShortObjectMap deactivatedBlockSet : deactivatedBlockSets) { deactivatedBlockSet.forEachEntry((id, positions) -> { @@ -282,13 +283,13 @@ private void deactivateBlocks() { private void checkForUnload() { PerformanceMonitor.startActivity("Unloading irrelevant chunks"); int unloaded = 0; - Iterator iterator = Iterators.concat( - Iterators.transform(chunkCache.keySet().iterator(), v -> new org.joml.Vector3i(v.x, v.y, v.z)), - loadingPipeline.getProcessingPosition().iterator()); + Iterator iterator = Iterators.concat( + Iterators.transform(chunkCache.keySet().iterator(), v -> new Vector3i(v.x(), v.y(), v.z())), + loadingPipeline.getProcessingPosition().iterator()); while (iterator.hasNext()) { - org.joml.Vector3ic pos = iterator.next(); + Vector3ic pos = iterator.next(); boolean keep = relevanceSystem.isChunkInRegions(pos); // TODO: move it to relevance system. - if (!keep && unloadChunkInternal(JomlUtil.from(pos))) { + if (!keep && unloadChunkInternal(pos)) { iterator.remove(); if (++unloaded >= UNLOAD_PER_FRAME) { break; @@ -302,10 +303,10 @@ private void checkForUnload() { PerformanceMonitor.endActivity(); } - private boolean unloadChunkInternal(Vector3i pos) { - if (loadingPipeline.isPositionProcessing(JomlUtil.from(pos))) { + private boolean unloadChunkInternal(Vector3ic pos) { + if (loadingPipeline.isPositionProcessing(pos)) { // Chunk hasn't been finished or changed, so just drop it. - loadingPipeline.stopProcessingAt(JomlUtil.from(pos)); + loadingPipeline.stopProcessingAt(pos); return false; } Chunk chunk = chunkCache.get(pos); @@ -313,7 +314,7 @@ private boolean unloadChunkInternal(Vector3i pos) { return false; } - worldEntity.send(new BeforeChunkUnload(JomlUtil.from(pos))); + worldEntity.send(new BeforeChunkUnload(pos)); storageManager.deactivateChunk(chunk); chunk.dispose(); @@ -337,7 +338,7 @@ void gatherBlockPositionsForDeactivate(Chunk chunk) { private TShortObjectMap createBatchBlockEventMappings(Chunk chunk) { TShortObjectMap batchBlockMap = new TShortObjectHashMap<>(); blockManager.listRegisteredBlocks().stream().filter(Block::isLifecycleEventsRequired).forEach(block -> - batchBlockMap.put(block.getId(), new TIntArrayList())); + batchBlockMap.put(block.getId(), new TIntArrayList())); ChunkBlockIterator i = chunk.getBlockIterator(); while (i.next()) { @@ -356,14 +357,8 @@ public Chunk getChunk(int x, int y, int z) { return getChunk(new Vector3i(x, y, z)); } - /** - * {@inheritDoc} - * - * @deprecated use {@link #getChunk(org.joml.Vector3ic)} instead. TODO replace with joml. - */ @Override - @Deprecated - public Chunk getChunk(Vector3i pos) { + public Chunk getChunk(Vector3ic pos) { Chunk chunk = chunkCache.get(pos); if (isChunkReady(chunk)) { return chunk; @@ -371,11 +366,6 @@ public Chunk getChunk(Vector3i pos) { return null; } - @Override - public Chunk getChunk(org.joml.Vector3ic pos) { - return getChunk(JomlUtil.from(pos)); - } - @Override public Collection getAllChunks() { return chunkCache.values(); @@ -399,7 +389,7 @@ public void dispose() { shutdown(); for (Chunk chunk : getAllChunks()) { - unloadChunkInternal(chunk.getPosition()); + unloadChunkInternal(chunk.getPosition(new Vector3i())); chunk.dispose(); } chunkCache.clear(); @@ -411,7 +401,7 @@ public void dispose() { } @Override - public boolean reloadChunk(Vector3i coords) { + public boolean reloadChunk(Vector3ic coords) { if (!chunkCache.containsKey(coords)) { return false; } @@ -431,7 +421,7 @@ public void purgeWorld() { loadingPipeline.shutdown(); unloadRequestTaskMaster.shutdown(new ChunkUnloadRequest(), true); getAllChunks().stream().filter(ManagedChunk::isReady).forEach(chunk -> { - worldEntity.send(new BeforeChunkUnload(chunk.getPosition(new org.joml.Vector3i()))); + worldEntity.send(new BeforeChunkUnload(chunk.getPosition(new Vector3i()))); storageManager.deactivateChunk(chunk); chunk.dispose(); }); @@ -441,38 +431,33 @@ public void purgeWorld() { loadingPipeline = new ChunkProcessingPipeline(this::getChunk, relevanceSystem.createChunkTaskComporator()); loadingPipeline.addStage( - ChunkTaskProvider.create("Chunk generate internal lightning", - (Consumer) InternalLightProcessor::generateInternalLighting)) - .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) - .addStage(ChunkTaskProvider.createMulti("Light merging", - chunks -> { - Chunk[] localchunks = chunks.toArray(new Chunk[0]); - return new LightMerger().merge(localchunks); - }, - pos -> StreamSupport.stream(new BlockRegion(pos).expand(1,1,1).spliterator(), false) - .map(org.joml.Vector3i::new) - .collect(Collectors.toSet()) - )) - .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); + ChunkTaskProvider.create("Chunk generate internal lightning", + (Consumer) InternalLightProcessor::generateInternalLighting)) + .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) + .addStage(ChunkTaskProvider.createMulti("Light merging", + chunks -> { + Chunk[] localchunks = chunks.toArray(new Chunk[0]); + return new LightMerger().merge(localchunks); + }, + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1, 1, 1).spliterator(), false) + .map(Vector3i::new) + .collect(Collectors.toSet()) + )) + .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); unloadRequestTaskMaster = TaskMaster.createFIFOTaskMaster("Chunk-Unloader", 8); ChunkMonitor.fireChunkProviderInitialized(this); for (ChunkRelevanceRegion chunkRelevanceRegion : relevanceSystem.getRegions()) { for (Vector3ic pos : chunkRelevanceRegion.getCurrentRegion()) { - createOrLoadChunk(JomlUtil.from(pos)); + createOrLoadChunk(pos); } chunkRelevanceRegion.setUpToDate(); } } - @Override - public boolean isChunkReady(Vector3i pos) { - return isChunkReady(chunkCache.get(pos)); - } - @Override public boolean isChunkReady(Vector3ic pos) { - return isChunkReady(chunkCache.get(JomlUtil.from(pos))); + return isChunkReady(chunkCache.get(pos)); } private boolean isChunkReady(Chunk chunk) { @@ -484,18 +469,18 @@ public void setRelevanceSystem(RelevanceSystem relevanceSystem) { this.relevanceSystem = relevanceSystem; loadingPipeline = new ChunkProcessingPipeline(this::getChunk, relevanceSystem.createChunkTaskComporator()); loadingPipeline.addStage( - ChunkTaskProvider.create("Chunk generate internal lightning", - (Consumer) InternalLightProcessor::generateInternalLighting)) - .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) - .addStage(ChunkTaskProvider.createMulti("Light merging", - chunks -> { - Chunk[] localchunks = chunks.toArray(new Chunk[0]); - return new LightMerger().merge(localchunks); - }, - pos -> StreamSupport.stream(new BlockRegion(pos).expand(1,1,1).spliterator(), false) - .map(org.joml.Vector3i::new) - .collect(Collectors.toCollection(Sets::newLinkedHashSet)) - )) - .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); + ChunkTaskProvider.create("Chunk generate internal lightning", + (Consumer) InternalLightProcessor::generateInternalLighting)) + .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) + .addStage(ChunkTaskProvider.createMulti("Light merging", + chunks -> { + Chunk[] localchunks = chunks.toArray(new Chunk[0]); + return new LightMerger().merge(localchunks); + }, + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1, 1, 1).spliterator(), false) + .map(Vector3i::new) + .collect(Collectors.toCollection(Sets::newLinkedHashSet)) + )) + .addStage(ChunkTaskProvider.create("Chunk ready", readyChunks::add)); } } diff --git a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java index b82f5c2f93e..94fd274bca4 100644 --- a/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java +++ b/engine/src/main/java/org/terasology/world/chunks/localChunkProvider/RelevanceSystem.java @@ -132,7 +132,7 @@ private void updateRelevance() { if (chunk != null) { chunkRelevanceRegion.checkIfChunkIsRelevant(chunk); } else { - chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); + chunkProvider.createOrLoadChunk(pos); } } chunkRelevanceRegion.setUpToDate(); @@ -182,7 +182,7 @@ public void addRelevanceEntity(EntityRef entity, Vector3ic distance, ChunkRegion if (chunk != null) { region.checkIfChunkIsRelevant(chunk); } else { - chunkProvider.createOrLoadChunk(JomlUtil.from(pos)); + chunkProvider.createOrLoadChunk(pos); } } ); diff --git a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java index a02b64f7230..1c64e9c86b1 100644 --- a/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java +++ b/engine/src/main/java/org/terasology/world/chunks/remoteChunkProvider/RemoteChunkProvider.java @@ -7,21 +7,16 @@ import com.google.common.collect.Maps; import com.google.common.collect.Queues; import org.joml.Vector3f; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.logic.players.LocalPlayer; -import org.terasology.math.ChunkMath; -import org.terasology.math.JomlUtil; -import org.terasology.math.Region3i; -import org.terasology.math.TeraMath; -import org.terasology.math.geom.Vector3i; import org.terasology.monitoring.chunk.ChunkMonitor; import org.terasology.world.block.BlockManager; import org.terasology.world.block.BlockRegion; import org.terasology.world.chunks.Chunk; -import org.terasology.world.chunks.ChunkConstants; import org.terasology.world.chunks.ChunkProvider; import org.terasology.world.chunks.Chunks; import org.terasology.world.chunks.event.BeforeChunkUnload; @@ -59,8 +54,8 @@ public class RemoteChunkProvider implements ChunkProvider { private static final Logger logger = LoggerFactory.getLogger(RemoteChunkProvider.class); private final BlockingQueue readyChunks = Queues.newLinkedBlockingQueue(); - private final BlockingQueue invalidateChunks = Queues.newLinkedBlockingQueue(); - private final Map chunkCache = Maps.newHashMap(); + private final BlockingQueue invalidateChunks = Queues.newLinkedBlockingQueue(); + private final Map chunkCache = Maps.newHashMap(); private final BlockManager blockManager; private final ChunkProcessingPipeline loadingPipeline; private EntityRef worldEntity = EntityRef.NULL; @@ -69,22 +64,22 @@ public class RemoteChunkProvider implements ChunkProvider { public RemoteChunkProvider(BlockManager blockManager, LocalPlayer localPlayer) { this.blockManager = blockManager; loadingPipeline = new ChunkProcessingPipeline(this::getChunk, - new LocalPlayerRelativeChunkComparator(localPlayer)); + new LocalPlayerRelativeChunkComparator(localPlayer)); loadingPipeline.addStage( - ChunkTaskProvider.create("Chunk generate internal lightning", - (Consumer) InternalLightProcessor::generateInternalLighting)) - .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) - .addStage(ChunkTaskProvider.createMulti("Light merging", - chunks -> { - Chunk[] localchunks = chunks.toArray(new Chunk[0]); - return new LightMerger().merge(localchunks); - }, - pos -> StreamSupport.stream(new BlockRegion(pos).expand(1, 1, 1).spliterator(), false) - .map(org.joml.Vector3i::new) - .collect(Collectors.toSet()) - )) - .addStage(ChunkTaskProvider.create("", readyChunks::add)); + ChunkTaskProvider.create("Chunk generate internal lightning", + (Consumer) InternalLightProcessor::generateInternalLighting)) + .addStage(ChunkTaskProvider.create("Chunk deflate", Chunk::deflate)) + .addStage(ChunkTaskProvider.createMulti("Light merging", + chunks -> { + Chunk[] localchunks = chunks.toArray(new Chunk[0]); + return new LightMerger().merge(localchunks); + }, + pos -> StreamSupport.stream(new BlockRegion(pos).expand(1, 1, 1).spliterator(), false) + .map(Vector3i::new) + .collect(Collectors.toSet()) + )) + .addStage(ChunkTaskProvider.create("", readyChunks::add)); ChunkMonitor.fireChunkProviderInitialized(this); } @@ -98,7 +93,7 @@ public void receiveChunk(final Chunk chunk) { loadingPipeline.invokePipeline(chunk); } - public void invalidateChunks(Vector3i pos) { + public void invalidateChunks(Vector3ic pos) { invalidateChunks.offer(pos); } @@ -109,25 +104,25 @@ public void update() { } Chunk chunk; while ((chunk = readyChunks.poll()) != null) { - Chunk oldChunk = chunkCache.put(JomlUtil.from(chunk.getPosition(new org.joml.Vector3i())), chunk); + Chunk oldChunk = chunkCache.put(chunk.getPosition(new Vector3i()), chunk); if (oldChunk != null) { oldChunk.dispose(); } chunk.markReady(); if (listener != null) { - listener.onChunkReady(chunk.getPosition(new org.joml.Vector3i())); + listener.onChunkReady(chunk.getPosition(new Vector3i())); } - worldEntity.send(new OnChunkLoaded(chunk.getPosition(new org.joml.Vector3i()))); + worldEntity.send(new OnChunkLoaded(chunk.getPosition(new Vector3i()))); } } private void checkForUnload() { - List positions = Lists.newArrayListWithCapacity(invalidateChunks.size()); + List positions = Lists.newArrayListWithCapacity(invalidateChunks.size()); invalidateChunks.drainTo(positions); - for (Vector3i pos : positions) { + for (Vector3ic pos : positions) { Chunk removed = chunkCache.remove(pos); if (removed != null && !removed.isReady()) { - worldEntity.send(new BeforeChunkUnload(JomlUtil.from(pos))); + worldEntity.send(new BeforeChunkUnload(pos)); removed.dispose(); } } @@ -139,7 +134,7 @@ public Chunk getChunk(int x, int y, int z) { } @Override - public Chunk getChunk(Vector3i chunkPos) { + public Chunk getChunk(Vector3ic chunkPos) { Chunk chunk = chunkCache.get(chunkPos); if (chunk != null && chunk.isReady()) { return chunk; @@ -147,20 +142,10 @@ public Chunk getChunk(Vector3i chunkPos) { return null; } - @Override - public Chunk getChunk(org.joml.Vector3ic pos) { - return getChunk(JomlUtil.from(pos)); - } - - @Override - public boolean isChunkReady(Vector3i pos) { - Chunk chunk = chunkCache.get(pos); - return chunk != null && chunk.isReady(); - } @Override public boolean isChunkReady(Vector3ic pos) { - Chunk chunk = chunkCache.get(JomlUtil.from(pos)); + Chunk chunk = chunkCache.get(pos); return chunk != null && chunk.isReady(); } @@ -171,7 +156,7 @@ public void dispose() { } @Override - public boolean reloadChunk(Vector3i pos) { + public boolean reloadChunk(Vector3ic pos) { return false; } @@ -196,23 +181,23 @@ public void restart() { } @Override - public ChunkViewCore getLocalView(Vector3i centerChunkPos) { - BlockRegion region = new BlockRegion(JomlUtil.from(centerChunkPos)).expand(Chunks.LOCAL_REGION_EXTENTS); + public ChunkViewCore getLocalView(Vector3ic centerChunkPos) { + BlockRegion region = new BlockRegion(centerChunkPos).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(centerChunkPos) != null) { - return createWorldView(region, Vector3i.one()); + return createWorldView(region, new Vector3i(1, 1, 1)); } return null; } @Override - public ChunkViewCore getSubviewAroundBlock(Vector3i blockPos, int extent) { - BlockRegion region = ChunkMath.getChunkRegionAroundWorldPos(JomlUtil.from(blockPos), extent); + public ChunkViewCore getSubviewAroundBlock(Vector3ic blockPos, int extent) { + BlockRegion region = Chunks.toChunkRegion(new BlockRegion(blockPos).expand(extent, extent, extent)); return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } @Override - public ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos) { - BlockRegion region = new BlockRegion(JomlUtil.from(chunkPos)).expand(Chunks.LOCAL_REGION_EXTENTS); + public ChunkViewCore getSubviewAroundChunk(Vector3ic chunkPos) { + BlockRegion region = new BlockRegion(chunkPos).expand(Chunks.LOCAL_REGION_EXTENTS); if (getChunk(chunkPos) != null) { return createWorldView(region, new Vector3i(-region.minX(), -region.minY(), -region.minZ())); } @@ -222,12 +207,12 @@ public ChunkViewCore getSubviewAroundChunk(Vector3i chunkPos) { private ChunkViewCore createWorldView(BlockRegion region, Vector3i offset) { Chunk[] chunks = new Chunk[region.getSizeX() * region.getSizeY() * region.getSizeZ()]; for (Vector3ic chunkPos : region) { - Chunk chunk = chunkCache.get(JomlUtil.from(chunkPos)); - chunkPos.sub(region.minX(), region.minY(), region.minZ(), new org.joml.Vector3i()); - int index = TeraMath.calculate3DArrayIndex(JomlUtil.from(chunkPos), JomlUtil.from(region.getSize(new org.joml.Vector3i()))); + Chunk chunk = chunkCache.get(chunkPos); + chunkPos.sub(region.minX(), region.minY(), region.minZ(), new Vector3i()); + int index = chunkPos.x() + region.getSizeX() * (chunkPos.z() + region.getSizeZ() * (chunkPos.y())); chunks[index] = chunk; } - return new ChunkViewCoreImpl(chunks, region, JomlUtil.from(offset), blockManager.getBlock(BlockManager.AIR_ID)); + return new ChunkViewCoreImpl(chunks, region, offset, blockManager.getBlock(BlockManager.AIR_ID)); } @Override @@ -248,7 +233,7 @@ public int compare(Future o1, Future o2) { } private int score(PositionFuture task) { - return (int) Chunks.toChunkPos(localPlayer.getPosition(new Vector3f()), new org.joml.Vector3i()).distance(task.getPosition()); + return (int) Chunks.toChunkPos(localPlayer.getPosition(new Vector3f()), new Vector3i()).distance(task.getPosition()); } } } diff --git a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java index c2c254bfd4e..b1d49477ea5 100644 --- a/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java +++ b/engine/src/main/java/org/terasology/world/internal/WorldProviderCoreImpl.java @@ -151,17 +151,17 @@ public void unregisterListener(WorldChangeListener listener) { @Override public ChunkViewCore getLocalView(Vector3ic chunkPos) { - return chunkProvider.getLocalView(JomlUtil.from(chunkPos)); + return chunkProvider.getLocalView(chunkPos); } @Override public ChunkViewCore getWorldViewAround(Vector3ic chunk) { - return chunkProvider.getSubviewAroundChunk(JomlUtil.from(chunk)); + return chunkProvider.getSubviewAroundChunk(chunk); } @Override public boolean isBlockRelevant(int x, int y, int z) { - return chunkProvider.isChunkReady(ChunkMath.calcChunkPos(x, y, z)); + return chunkProvider.isChunkReady(Chunks.toChunkPos(x, y, z, new Vector3i())); } @Override diff --git a/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java b/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java index 99e6a2b2858..278a221e47a 100644 --- a/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java +++ b/engine/src/main/java/org/terasology/world/propagation/LocalChunkView.java @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.world.propagation; +import org.joml.Vector3i; import org.joml.Vector3ic; import org.terasology.world.block.Block; import org.terasology.world.chunks.Chunk; @@ -15,12 +16,12 @@ public class LocalChunkView implements PropagatorWorldView { private PropagationRules rules; private Chunk[] chunks; - private final org.joml.Vector3i topLeft; + private final Vector3i topLeft; public LocalChunkView(Chunk[] chunks, PropagationRules rules) { this.chunks = chunks; this.rules = rules; - topLeft = chunks[0].getPosition(new org.joml.Vector3i()); + topLeft = chunks[0].getPosition(new Vector3i()); } /** @@ -43,7 +44,7 @@ public byte getValueAt(Vector3ic pos) { } Chunk chunk = chunks[index]; if (chunk != null) { - return rules.getValue(chunk, Chunks.toRelative(pos, new org.joml.Vector3i())); + return rules.getValue(chunk, Chunks.toRelative(pos, new Vector3i())); } return UNAVAILABLE; } @@ -52,7 +53,7 @@ public byte getValueAt(Vector3ic pos) { public void setValueAt(Vector3ic pos, byte value) { Chunk chunk = chunks[chunkIndexOf(pos)]; if (chunk != null) { - rules.setValue(chunk, Chunks.toRelative(pos, new org.joml.Vector3i()), value); + rules.setValue(chunk, Chunks.toRelative(pos, new Vector3i()), value); } } @@ -61,7 +62,7 @@ public Block getBlockAt(Vector3ic pos) { int index = chunkIndexOf(pos); Chunk chunk = chunks[index]; if (chunk != null) { - return chunk.getBlock(Chunks.toRelative(pos, new org.joml.Vector3i())); + return chunk.getBlock(Chunks.toRelative(pos, new Vector3i())); } return null; } From ddf6c7799e0c64a109cb4eb9fdbae9206e9747f7 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 6 Feb 2021 14:28:34 -0800 Subject: [PATCH 213/259] feat(JOML): remove tera-assert (#4459) --- .../org/terasology/testUtil/TeraAssert.java | 144 ------------------ .../entitySystem/OwnershipHelperTest.java | 14 +- .../serializers/VectorTypeSerializerTest.java | 106 +++---------- 3 files changed, 30 insertions(+), 234 deletions(-) delete mode 100644 engine-tests/src/main/java/org/terasology/testUtil/TeraAssert.java diff --git a/engine-tests/src/main/java/org/terasology/testUtil/TeraAssert.java b/engine-tests/src/main/java/org/terasology/testUtil/TeraAssert.java deleted file mode 100644 index 18e1a52c0d0..00000000000 --- a/engine-tests/src/main/java/org/terasology/testUtil/TeraAssert.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.terasology.testUtil; - -import com.google.common.collect.Lists; -import org.joml.Quaternionfc; -import org.joml.Vector2fc; -import org.joml.Vector3fc; -import org.joml.Vector4fc; -import org.junit.jupiter.api.Assertions; -import org.terasology.math.geom.Quat4f; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector4f; - -import java.util.Collection; -import java.util.List; -import java.util.function.Supplier; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -/** - * - */ -public final class TeraAssert { - private TeraAssert() { - } - - public static void assertEqualsContent(Collection expected, Collection actual) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - List copyActual = Lists.newArrayList(actual); - for (Object obj : expected) { - assertTrue(copyActual.remove(obj), () -> "Missing element: " + obj); - } - assertTrue(copyActual.isEmpty(), () -> "Unexpected additional elements: " + copyActual.toString()); - } - } - - public static void assertEquals(Vector3f expected, Vector3f actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x, actual.x, error, errorMessageSupplier); - Assertions.assertEquals(expected.y, actual.y, error, errorMessageSupplier); - Assertions.assertEquals(expected.z, actual.z, error, errorMessageSupplier); - } - } - - public static void assertEquals(Vector2f expected, Vector2f actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x, actual.x, error, errorMessageSupplier); - Assertions.assertEquals(expected.y, actual.y, error, errorMessageSupplier); - } - } - - public static void assertEquals(Vector2fc expected, Vector2fc actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x(), actual.x(), error, errorMessageSupplier); - Assertions.assertEquals(expected.y(), actual.y(), error, errorMessageSupplier); - } - } - - - public static void assertEquals(Vector3fc expected, Vector3fc actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x(), actual.x(), error, errorMessageSupplier); - Assertions.assertEquals(expected.y(), actual.y(), error, errorMessageSupplier); - Assertions.assertEquals(expected.z(), actual.z(), error, errorMessageSupplier); - } - } - - public static void assertEquals(Vector4f expected, Vector4f actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x, actual.x, error, errorMessageSupplier); - Assertions.assertEquals(expected.y, actual.y, error, errorMessageSupplier); - Assertions.assertEquals(expected.z, actual.z, error, errorMessageSupplier); - Assertions.assertEquals(expected.w, actual.w, error, errorMessageSupplier); - } - } - - public static void assertEquals(Vector4fc expected, Vector4fc actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x(), actual.x(), error, errorMessageSupplier); - Assertions.assertEquals(expected.y(), actual.y(), error, errorMessageSupplier); - Assertions.assertEquals(expected.z(), actual.z(), error, errorMessageSupplier); - Assertions.assertEquals(expected.w(), actual.w(), error, errorMessageSupplier); - } - } - - - public static void assertEquals(Quaternionfc expected, Quaternionfc actual, float error) { - if (expected == null) { - assertNull(actual); - } else { - assertNotNull(actual); - Supplier errorMessageSupplier = () -> "Expected " + expected + ", actual" + actual; - Assertions.assertEquals(expected.x(), actual.x(), error, errorMessageSupplier); - Assertions.assertEquals(expected.y(), actual.y(), error, errorMessageSupplier); - Assertions.assertEquals(expected.z(), actual.z(), error, errorMessageSupplier); - Assertions.assertEquals(expected.w(), actual.w(), error, errorMessageSupplier); - } - } -} diff --git a/engine-tests/src/test/java/org/terasology/entitySystem/OwnershipHelperTest.java b/engine-tests/src/test/java/org/terasology/entitySystem/OwnershipHelperTest.java index 0a36f3fea33..d45576f8927 100644 --- a/engine-tests/src/test/java/org/terasology/entitySystem/OwnershipHelperTest.java +++ b/engine-tests/src/test/java/org/terasology/entitySystem/OwnershipHelperTest.java @@ -31,8 +31,16 @@ import org.terasology.registry.CoreRegistry; import org.terasology.testUtil.ModuleManagerFactory; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -import static org.terasology.testUtil.TeraAssert.assertEqualsContent; + /** */ @@ -67,6 +75,8 @@ public void testListsOwnedEntities() { EntityRef ownerEntity = entityManager.create(ownerComp); OwnershipHelper helper = new OwnershipHelper(entityManager.getComponentLibrary()); - assertEqualsContent(Lists.newArrayList(ownedEntity), helper.listOwnedEntities(ownerEntity)); + ArrayList target = Lists.newArrayList(helper.listOwnedEntities(ownerEntity)); + assertEquals(target.size(), 1); + assertEquals(target.get(0), ownedEntity); } } diff --git a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java index b731d4c514f..6c6cfadb56e 100644 --- a/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java +++ b/engine-tests/src/test/java/org/terasology/persistence/serializers/VectorTypeSerializerTest.java @@ -2,40 +2,29 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.persistence.serializers; +import org.joml.Vector2f; import org.joml.Vector2fc; +import org.joml.Vector3f; import org.joml.Vector3fc; +import org.joml.Vector4f; import org.joml.Vector4fc; import org.junit.jupiter.api.Test; import org.terasology.ModuleEnvironmentTest; -import org.terasology.math.geom.Vector2f; -import org.terasology.math.geom.Vector3f; -import org.terasology.math.geom.Vector4f; import org.terasology.naming.Name; import org.terasology.persistence.ModuleContext; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.reflection.TypeInfo; -import org.terasology.testUtil.TeraAssert; - -import static org.terasology.joml.test.VectorAssert.assertEquals; - import java.io.IOException; -public class VectorTypeSerializerTest extends ModuleEnvironmentTest { +import static org.terasology.joml.test.VectorAssert.assertEquals; - static class TestObject{ +public class VectorTypeSerializerTest extends ModuleEnvironmentTest { + static class TestObject { public Vector3f v1; public Vector2f v2; public Vector4f v3; - public org.joml.Vector3f v11; - public org.joml.Vector2f v22; - public org.joml.Vector4f v33; - } - static class TestObject1 { - public org.joml.Vector3f v1; - public org.joml.Vector2f v2; - public org.joml.Vector4f v3; } static class TestObject2 { @@ -61,61 +50,17 @@ public void setup() { @Test public void testSerializationConstant() throws IOException { TestObject2 a = new TestObject2(); - a.v1 = new org.joml.Vector3f(1.0f, 2.0f, 3.0f); - a.v2 = new org.joml.Vector4f(1.0f, 2.0f, 3.0f, 5.0f); - a.v3 = new org.joml.Vector2f(1.0f, 2.0f); + a.v1 = new Vector3f(1.0f, 2.0f, 3.0f); + a.v2 = new Vector4f(1.0f, 2.0f, 3.0f, 5.0f); + a.v3 = new Vector2f(1.0f, 2.0f); String data = gsonSerializer.toJson(a, new TypeInfo() { }); TestObject2 o = gsonSerializer.fromJson(data, new TypeInfo() { }); - assertEquals(o.v1, new org.joml.Vector3f(1.0f, 2.0f, 3.0f), .00001f); - assertEquals(o.v2, new org.joml.Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); - assertEquals(o.v3, new org.joml.Vector2f(1.0f, 2.0f), .00001f); - } - - @Test - public void testJsonSerializeRemapped() throws IOException { - TestObject a = new TestObject(); - a.v1 = new Vector3f(11.5f, 13.15f, 3); - a.v2 = new Vector2f(12, 13f); - a.v3 = new Vector4f(12, 12.2f, 3f, 15.5f); - a.v11 = new org.joml.Vector3f(11.5f, 13.15f, 3); - a.v22 = new org.joml.Vector2f(12, 13f); - a.v33 = new org.joml.Vector4f(12, 12.2f, 3f, 15.5f); - - String data = gsonSerializer.toJson(a, new TypeInfo() { - }); - - TestObject1 o = gsonSerializer.fromJson(data, new TypeInfo() { - }); - - assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); - assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - - } - - @Test - public void testProtobufSerializeRemapped() throws IOException { - TestObject a = new TestObject(); - a.v1 = new Vector3f(11.5f, 13.15f, 3); - a.v2 = new Vector2f(12, 13f); - a.v3 = new Vector4f(12, 12.2f, 3f, 15.5f); - a.v11 = new org.joml.Vector3f(11.5f, 13.15f, 3); - a.v22 = new org.joml.Vector2f(12, 13f); - a.v33 = new org.joml.Vector4f(12, 12.2f, 3f, 15.5f); - - byte[] data = protobufSerializer.toBytes(a, new TypeInfo() { - }); - - TestObject1 o = protobufSerializer.fromBytes(data, new TypeInfo() { - }); - - assertEquals(o.v1, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - assertEquals(o.v2, new org.joml.Vector2f(12f, 13f), .00001f); - assertEquals(o.v3, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - + assertEquals(o.v1, new Vector3f(1.0f, 2.0f, 3.0f), .00001f); + assertEquals(o.v2, new Vector4f(1.0f, 2.0f, 3.0f, 5.0f), .00001f); + assertEquals(o.v3, new Vector2f(1.0f, 2.0f), .00001f); } @Test @@ -124,9 +69,6 @@ public void testJsonSerialize() throws IOException { a.v1 = new Vector3f(11.5f, 13.15f, 3); a.v2 = new Vector2f(12, 13f); a.v3 = new Vector4f(12, 12.2f, 3f, 15.5f); - a.v11 = new org.joml.Vector3f(11.5f, 13.15f, 3); - a.v22 = new org.joml.Vector2f(12, 13f); - a.v33 = new org.joml.Vector4f(12, 12.2f, 3f, 15.5f); String data = gsonSerializer.toJson(a, new TypeInfo() { }); @@ -134,13 +76,9 @@ public void testJsonSerialize() throws IOException { TestObject o = gsonSerializer.fromJson(data, new TypeInfo() { }); - TeraAssert.assertEquals(o.v1, new Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - - assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); - assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v1, new Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); + assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } @Test @@ -149,9 +87,6 @@ public void testProtobufSerialize() throws IOException { a.v1 = new Vector3f(11.5f, 13.15f, 3); a.v2 = new Vector2f(12, 13f); a.v3 = new Vector4f(12, 12.2f, 3f, 15.5f); - a.v11 = new org.joml.Vector3f(11.5f, 13.15f, 3); - a.v22 = new org.joml.Vector2f(12, 13f); - a.v33 = new org.joml.Vector4f(12, 12.2f, 3f, 15.5f); byte[] bytes = protobufSerializer.toBytes(a, new TypeInfo() { }); @@ -159,13 +94,8 @@ public void testProtobufSerialize() throws IOException { TestObject o = protobufSerializer.fromBytes(bytes, new TypeInfo() { }); - TeraAssert.assertEquals(o.v1, new Vector3f(11.5f, 13.15f, 3), .00001f); - TeraAssert.assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); - TeraAssert.assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); - - assertEquals(o.v11, new org.joml.Vector3f(11.5f, 13.15f, 3), .00001f); - assertEquals(o.v22, new org.joml.Vector2f(12f, 13f), .00001f); - assertEquals(o.v33, new org.joml.Vector4f(12, 12.2f, 3f, 15.5f), .00001f); + assertEquals(o.v1, new Vector3f(11.5f, 13.15f, 3), .00001f); + assertEquals(o.v2, new Vector2f(12f, 13f), .00001f); + assertEquals(o.v3, new Vector4f(12, 12.2f, 3f, 15.5f), .00001f); } - } From 077020fa31aedf48bf2aad186a6a348c5cbc637e Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Sun, 7 Feb 2021 00:42:16 +0100 Subject: [PATCH 214/259] doc: add conventional commits to contributing guidelines (#4410) --- .github/CONTRIBUTING.md | 134 +++++++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 35 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 369f2aed4b4..da292837ad0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,5 +1,4 @@ -Contributing to Terasology -================================== +# Contributing to Terasology If you would like to contribute code, documentation, or other assets you can do so through GitHub by forking the repository and sending a pull request (PR). You can also simply report issues (bugs), but please search for any previous reports first. @@ -7,8 +6,8 @@ If you would like to contribute code, documentation, or other assets you can do Read on for an overview and [check the wiki for more details](https://github.com/MovingBlocks/Terasology/wiki). For questions please join us in our [forum](http://forum.terasology.org/forum/) or on `#terasology` (irc.freenode.net). -File an Issue -------------- +## File an Issue + You can report bugs and feature requests to [GitHub Issues](https://github.com/MovingBlocks/Terasology/issues). As mentioned please look for a similar existing issue before submitting a new one. For finding easy to do issues to start with look at the [Good First Issue](https://github.com/MovingBlocks/Terasology/labels/Good%20First%20Issue) issues. @@ -17,40 +16,105 @@ We prefer questions and support requests be posted in the [forum](http://forum.t __Please provide as much information as possible to help us solve problems and answer questions better!__ -Commits and Commit Messages ---------------------------- -Follow these guidelines when creating public commits and writing commit messages. +## PR Title / Commit Message Guidelines + +We try to follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) style for commit messages and pull request titles. +This leads to **more readable messages** that are easy to follow when looking through the **project history**. +But also, we use the git commit messages to **generate the Terasology change log**. + +### Commit Message Format +Each commit message consists of a **header**, a **body** and a **footer**. The header has a special +format that includes a **type**, a **scope** and a **subject**: + +``` +(): + + + +