diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index fe67791f2..24954f4ee 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -83,7 +83,7 @@ body: attributes: label: Fawe Version description: What version of Fawe are you running? (`/version FastAsyncWorldEdit`) - placeholder: "For example: FastAsyncWorldEdit version 1.17-89;8c01959" + placeholder: "For example: FastAsyncWorldEdit version 2.0.0-SNAPSHOT-1" validations: required: true diff --git a/.github/stale.yml b/.github/stale.yml index 7d95c1f66..c6ad3e8fe 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,4 +1,4 @@ -daysUntilStale: 60 +daysUntilStale: 30 daysUntilClose: 7 only: issues exemptLabels: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 30201b465..b56c1367d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,34 +1,47 @@ -name: "build" +name: build -on: ["pull_request", "push"] +on: [pull_request, push] jobs: build: - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest steps: - - name: "Checkout Repository" - uses: "actions/checkout@v2.3.4" - - name : "Validate Gradle Wrapper" - uses : "gradle/wrapper-validation-action@v1.0.4" - - name: "Grab SHA" - uses: "benjlevesque/short-sha@v1.2" - id: "short-sha" + - name: Checkout Repository + uses: actions/checkout@v2.4.0 + - name : Validate Gradle Wrapper + uses : gradle/wrapper-validation-action@v1.0.4 + - name: Setup Java + uses: actions/setup-java@v2.4.0 with: - length: "7" - - name: "Echo SHA" - run: "echo $SHA" + distribution: temurin + cache: gradle + java-version: 17 + - name: Clean Build + run: ./gradlew clean build --no-daemon + - name: Determine release status + if: ${{ runner.os == 'Linux' }} + run: | + if [ "$(./gradlew properties | awk '/^version:/ { print $2; }' | grep '\-SNAPSHOT')" ]; then + echo "STATUS=snapshot" >> $GITHUB_ENV + else + echo "STATUS=release" >> $GITHUB_ENV + fi + - name: Publish Release + if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18'}} + run: ./gradlew publishToSonatype closeSonatypeStagingRepository env: - SHA: "${{ steps.short-sha.outputs.sha }}" - - name: "Setup Java" - uses: "actions/setup-java@v2.3.1" - with: - distribution: "temurin" - cache: 'gradle' - java-version: "17" - - name: "Clean Build" - run: "./gradlew clean build --no-daemon" + ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} + - name: Publish Snapshot + if: ${{ runner.os == 'Linux' && env.STATUS != 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18' }} + run: ./gradlew publishToSonatype + env: + ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} - name: Archive Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v2.3.1 with: - name: FastAsyncWorldEdit-Bukkit-1.17-${{ env.SHA }} - path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-1.17-${{ env.SHA }}.jar + name: FastAsyncWorldEdit-Bukkit-SNAPSHOT + path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml new file mode 100644 index 000000000..b4feba220 --- /dev/null +++ b/.github/workflows/rebase.yml @@ -0,0 +1,20 @@ +name: Rebase Pull Request +on: + issue_comment: + types: [created] + +jobs: + rebase: + name: Rebase + if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') && github.event.comment.author_association == 'MEMBER' + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v2.4.0 + with: + token: ${{ secrets.REBASE_TOKEN }} + fetch-depth: 0 + - name: Automatic Rebase + uses: cirrus-actions/rebase@1.5 + env: + GITHUB_TOKEN: ${{ secrets.REBASE_TOKEN }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 021ad30ce..6beea8078 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -1,14 +1,14 @@ -name: "draft release" +name: draft release on: push: branches: - - "2.0.0" + - main jobs: update_release_draft: - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest steps: - - uses: "release-drafter/release-drafter@v5.15.0" + - uses: release-drafter/release-drafter@v5.15.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Annotation-Explanation.adoc b/Annotation-Explanation.adoc new file mode 100644 index 000000000..100541872 --- /dev/null +++ b/Annotation-Explanation.adoc @@ -0,0 +1,54 @@ +:toc: +:toclevels: 2 + += Fawe annotations explained + +If we have modified parts of the WorldEdit codebase, we considered annotating it with different styles of comments, which +are explained in this document. + +== In-line annotations + +[source,java] +----------------- +public static Player adapt(com.sk89q.worldedit.entity.Player player) { + //FAWE start - Get player from PlayerProxy instead of BukkitPlayer if null + player = PlayerProxy.unwrap(player); + return player == null ? null : ((BukkitPlayer) player).getPlayer(); + //FAWE end +} +----------------- +The `-sources` jar retains comments, if you add the FAWE API to your maven or gradle project, you can view differences between the projects with ease. +Behind the `//FAWE start - ` you can find a comment what has been changed and why it has been changed. + +== Block annotations + +[source,java] +----------------- +//FAWE start + @Override + public void setPermission(String permission, boolean value) { + } +//FAWE end +----------------- +Annotations can cover whole methods or go beyond the method and wrap around several added methods. + +== Package annotations +Class additions are added under the `com.fastasyncworldedit` namespace, but sometimes classes need to be added in package private. +If that is done, you can find a `package-info.java` file within the package affected that outlines FAWE added classes: +[source,java] +----------------- +/** +* The following classes are FAWE additions: +* +* @see com.sk89q.worldedit.world.block.BlockTypesCache +*/ +package com.sk89q.worldedit.world.block; +----------------- + +== Undocumented annotations +Specific changes are not annotated: + +* `com.fastasyncworldedit.core.configuration.Caption` in `com.sk89q.worldedit` packages have been changed from +`com.sk89q.worldedit.util.formatting.text.Text` to allow the usage of color codes for messages. + +* Certain Log4J loggers have been adjusted to use the proper format of placeholders. diff --git a/COMPILING.md b/COMPILING.md index 0f2f9faa4..87bd2fe20 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -1,12 +1,12 @@ Compiling ========= -You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 16 installed. Gradle will download JDK 16 specifically if needed, +You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed, but it needs some version of Java to bootstrap from. Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 16. -You can get the JDK 16 [here](https://adoptium.net/). +You can get the JDK 17 [here](https://adoptium.net/). The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules: @@ -16,10 +16,6 @@ The build process uses Gradle, which you do *not* need to download. FastAsyncWor ## To compile... -### NMS -FastAsyncWorldEdit uses NMS (net.minecraft.server) code in a variety of spots. NMS is not distributed via maven and therefore FastAsyncWorldEdit may not build without errors if you didn't install it into your local repository beforehand. -You can do that by either running Spigot's [BuildTools](https://www.spigotmc.org/wiki/buildtools/) targeting the versions needed or using Paper's [paperclip](https://papermc.io/downloads) with `java -Dpaperclip.install=true -jar paperclip.jar`. - ### On Windows 1. Shift + right-click the folder with FastAsyncWorldEdit's files and click "Open command prompt". @@ -38,13 +34,13 @@ You will find: * FastAsyncWorldEdit for Bukkit in **worldedit-bukkit/build/libs** * the CLI version in **worldedit-cli/build/libs** -If you want to use FastAsyncWorldEdit, use the `FastAsyncWorldEdit-1.17-` version obtained in **worldedit-bukkit/build/libs**. +If you want to use FastAsyncWorldEdit, use the `FastAsyncWorldEdit-` version obtained in **worldedit-bukkit/build/libs**. (The `-#` version includes FastAsyncWorldEdit + necessary libraries.) ## Other commands -* `gradlew idea` will generate an [IntelliJ IDEA](http://www.jetbrains.com/idea/) module for each folder. +* `gradlew idea` will generate an [IntelliJ IDEA](https://www.jetbrains.com/idea/) module for each folder. _Possibly broken_: * `gradlew eclipse` will generate an [Eclipse](https://www.eclipse.org/downloads/) project for each folder. diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 466a35458..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,10 +0,0 @@ -pipeline { - agent any - stages { - stage('Build pull request') { - steps { - sh './gradlew clean build' - } - } - } -} diff --git a/README.md b/README.md index d5f0ffe60..3cb346f35 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ FastAsyncWorldEdit is a fork of WorldEdit that has huge speed and memory improve * Use it in creative, survival in single player or on your server. * Use it on your Minecraft server to fix grieving and mistakes. -Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot, Paper, and Tuinity. +Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot and Paper. ## Download FastAsyncWorldEdit * Spigot: https://www.spigotmc.org/resources/fast-async-worldedit.13932/ @@ -24,8 +24,8 @@ Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot, Pap * [Wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki) * [Report Issue](https://github.com/IntellectualSites/FastAsyncWorldEdit/issues) * [Crowdin (Translations)](https://intellectualsites.crowdin.com/fastasyncworldedit) -* [JavaDocs for the -bukkit module](https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Bukkit-Javadocs/javadoc/) -* [JavaDocs for the -core module](https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Core-Javadocs/javadoc/) +* [JavaDocs for the -bukkit module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Bukkit/latest/index.html) +* [JavaDocs for the -core module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Core/latest/index.html) ## Edit The Code diff --git a/build.gradle.kts b/build.gradle.kts index 018b45f39..c52c082a2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,11 @@ import org.ajoberstar.grgit.Grgit import java.time.format.DateTimeFormatter import org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED +import java.net.URI + +plugins { + id("io.github.gradle-nexus.publish-plugin") version "1.1.0" +} logger.lifecycle(""" ******************************************* @@ -17,7 +22,8 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("1.17") +var rootVersion by extra("2.0.0") +var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") var date: String by extra("") @@ -27,11 +33,10 @@ ext { } date = git.head().dateTime.format(DateTimeFormatter.ofPattern("yy.MM.dd")) revision = "-${git.head().abbreviatedId}" - val commit: String? = git.head().abbreviatedId buildNumber = if (project.hasProperty("buildnumber")) { - project.properties["buildnumber"] as String + snapshot + "-" + project.properties["buildnumber"] as String } else { - commit.toString() + project.properties["snapshot"] as String } } @@ -66,3 +71,12 @@ allprojects { } applyCommonConfiguration() + +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index cd2119fe7..71895e12c 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -8,14 +8,17 @@ plugins { repositories { mavenCentral() gradlePluginPortal() - maven { - name = "PaperMC" - url = uri("https://papermc.io/repo/repository/maven-public/") - } maven { name = "EngineHub" url = uri("https://maven.enginehub.org/repo/") } + maven { + name = "PaperMC" + url = uri("https://papermc.io/repo/repository/maven-public/") + content { + includeGroupByRegex("io\\.papermc\\..*") + } + } } val properties = Properties().also { props -> @@ -28,5 +31,11 @@ dependencies { implementation(gradleApi()) implementation("org.ajoberstar.grgit:grgit-gradle:4.1.1") implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.1.14") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.3.3") +} + +kotlin { + jvmToolchain { + (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(17)) + } } diff --git a/buildSrc/src/main/kotlin/AdapterConfig.kt b/buildSrc/src/main/kotlin/AdapterConfig.kt index 575071a42..d6fc3df31 100644 --- a/buildSrc/src/main/kotlin/AdapterConfig.kt +++ b/buildSrc/src/main/kotlin/AdapterConfig.kt @@ -5,9 +5,7 @@ import org.gradle.kotlin.dsl.dependencies // For specific version pinning, see // https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ -fun Project.applyPaperweightAdapterConfiguration( - paperVersion: String -) { +fun Project.applyPaperweightAdapterConfiguration() { applyCommonConfiguration() apply(plugin = "java-library") applyCommonJavaConfiguration( @@ -17,7 +15,6 @@ fun Project.applyPaperweightAdapterConfiguration( apply(plugin = "io.papermc.paperweight.userdev") dependencies { - paperDevBundle(paperVersion) "implementation"(project(":worldedit-bukkit")) } diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt index d746fcefa..6e59e7f05 100644 --- a/buildSrc/src/main/kotlin/CommonConfig.kt +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -10,12 +10,7 @@ fun Project.applyCommonConfiguration() { version = rootProject.version repositories { - mavenLocal() mavenCentral() - maven { - name = "IntellectualSites" - url = uri("https://mvn.intellectualsites.com/content/groups/public/") - } maven { name = "EngineHub" url = uri("https://maven.enginehub.org/repo/") @@ -32,6 +27,7 @@ fun Project.applyCommonConfiguration() { name = "Athion" url = uri("https://ci.athion.net/plugin/repository/tools/") } + mavenLocal() } configurations.all { @@ -42,7 +38,7 @@ fun Project.applyCommonConfiguration() { plugins.withId("java") { the().toolchain { - languageVersion.set(JavaLanguageVersion.of(16)) + languageVersion.set(JavaLanguageVersion.of(17)) } } @@ -54,15 +50,15 @@ fun Project.applyCommonConfiguration() { continue } add(conf.name, "com.google.guava:guava") { - version { require("21.0") } + version { require("31.0.1-jre") } because("Mojang provides Guava") } add(conf.name, "com.google.code.gson:gson") { - version { require("2.8.0") } + version { require("2.8.8") } because("Mojang provides Gson") } add(conf.name, "it.unimi.dsi:fastutil") { - version { require("8.2.1") } + version { require("8.5.6") } because("Mojang provides FastUtil") } } diff --git a/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index b0029429c..00b87806f 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -24,7 +24,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean val disabledLint = listOf( "processing", "path", "fallthrough", "serial" ) - options.release.set(11) + options.release.set(17) options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" }) options.isDeprecation = true options.encoding = "UTF-8" @@ -32,7 +32,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean } configurations.all { - attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16) + attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } tasks.withType().configureEach { @@ -60,13 +60,12 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean options.encoding = "UTF-8" links( "https://javadoc.io/doc/com.google.code.findbugs/jsr305/3.0.2/", - "https://jd.adventure.kyori.net/api/4.9.1/", - "https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/2.14.1/", - "https://javadoc.io/doc/com.google.guava/guava/21.0/", + "https://jd.adventure.kyori.net/api/latest/", + "https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/latest/index.html", "https://www.antlr.org/api/Java/", "https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/", "https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/", - "https://papermc.io/javadocs/paper/1.17/", + "https://papermc.io/javadocs/paper/1.18/", "https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Core-Javadocs/javadoc/" // needed for other module linking ) } diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index e0eeb117d..caae699d7 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -21,6 +21,8 @@ import org.gradle.kotlin.dsl.invoke import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.the +import org.gradle.plugins.signing.SigningExtension import javax.inject.Inject fun Project.applyLibrariesConfiguration() { @@ -28,6 +30,7 @@ fun Project.applyLibrariesConfiguration() { apply(plugin = "java-base") apply(plugin = "maven-publish") apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "signing") configurations { create("shade") @@ -49,6 +52,7 @@ fun Project.applyLibrariesConfiguration() { dependencies { exclude(dependency("com.google.guava:guava")) exclude(dependency("com.google.code.gson:gson")) + exclude(dependency("com.google.errorprone:error_prone_annotations")) exclude(dependency("org.checkerframework:checker-qual")) exclude(dependency("org.apache.logging.log4j:log4j-api")) exclude(dependency("com.google.code.findbugs:jsr305")) @@ -94,8 +98,14 @@ fun Project.applyLibrariesConfiguration() { archiveClassifier.set("sources") } + // This a dummy jar to comply with the requirements of the OSSRH, + // libs are not API and therefore no "proper" javadoc jar is necessary + tasks.register("javadocJar") { + archiveClassifier.set("javadoc") + } + tasks.named("assemble").configure { - dependsOn("jar", "sourcesJar") + dependsOn("jar", "sourcesJar", "javadocJar") } project.apply() @@ -112,7 +122,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } outgoing.artifact(tasks.named("jar")) } @@ -127,7 +137,7 @@ fun Project.applyLibrariesConfiguration() { attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11) + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } outgoing.artifact(tasks.named("jar")) } @@ -146,6 +156,20 @@ fun Project.applyLibrariesConfiguration() { outgoing.artifact(tasks.named("sourcesJar")) } + val javadocElements = project.configurations.register("javadocElements") { + isVisible = false + description = "Javadoc elements for libs" + isCanBeResolved = false + isCanBeConsumed = true + attributes { + attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME)) + attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION)) + attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) + attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.JAVADOC)) + } + outgoing.artifact(tasks.named("javadocJar")) + } + libsComponent.addVariantsFromConfiguration(apiElements.get()) { mapToMavenScope("compile") } @@ -158,6 +182,22 @@ fun Project.applyLibrariesConfiguration() { mapToMavenScope("runtime") } + libsComponent.addVariantsFromConfiguration(javadocElements.get()) { + mapToMavenScope("runtime") + } + + val publishingExtension = the() + + configure { + if (!version.toString().endsWith("-SNAPSHOT")) { + val signingKey: String? by project + val signingPassword: String? by project + useInMemoryPgpKeys(signingKey, signingPassword) + isRequired + sign(publishingExtension.publications) + } + } + configure { publications { register("maven") { @@ -212,33 +252,6 @@ fun Project.applyLibrariesConfiguration() { } } } - - repositories { - mavenLocal() - val nexusUsername: String? by project - val nexusPassword: String? by project - if (nexusUsername != null && nexusPassword != null) { - maven { - val releasesRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/releases/" - val snapshotRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/snapshots/" - /* Commenting this out for now - Fawe currently does not user semver or any sort of versioning that - differentiates between snapshots and releases, API & (past) deployment wise, this will come with a next major release. - url = uri( - if (version.toString().endsWith("-SNAPSHOT")) snapshotRepositoryUrl - else releasesRepositoryUrl - ) - */ - url = uri(releasesRepositoryUrl) - - credentials { - username = nexusUsername - password = nexusPassword - } - } - } else { - logger.warn("No nexus repository is added; nexusUsername or nexusPassword is null.") - } - } } } diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 6f805aece..eafb5681f 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -12,6 +12,7 @@ import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.the +import org.gradle.plugins.signing.SigningExtension fun Project.applyPlatformAndCoreConfiguration() { applyCommonConfiguration() @@ -20,6 +21,7 @@ fun Project.applyPlatformAndCoreConfiguration() { apply(plugin = "idea") apply(plugin = "maven-publish") apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "signing") applyCommonJavaConfiguration( sourcesJar = name in setOf("worldedit-core", "worldedit-bukkit"), @@ -45,6 +47,18 @@ fun Project.applyPlatformAndCoreConfiguration() { skip() } + val publishingExtension = the() + + configure { + if (!version.toString().endsWith("-SNAPSHOT")) { + val signingKey: String? by project + val signingPassword: String? by project + useInMemoryPgpKeys(signingKey, signingPassword) + isRequired + sign(publishingExtension.publications) + } + } + configure { publications { register("maven") { @@ -99,33 +113,6 @@ fun Project.applyPlatformAndCoreConfiguration() { } } } - - repositories { - mavenLocal() - val nexusUsername: String? by project - val nexusPassword: String? by project - if (nexusUsername != null && nexusPassword != null) { - maven { - val releasesRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/releases/" - val snapshotRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/snapshots/" - /* Commenting this out for now - Fawe currently does not user semver or any sort of versioning that - differentiates between snapshots and releases, API & (past) deployment wise, this will come with a next major release. - url = uri( - if (version.toString().endsWith("-SNAPSHOT")) snapshotRepositoryUrl - else releasesRepositoryUrl - ) - */ - url = uri(releasesRepositoryUrl) - - credentials { - username = nexusUsername - password = nexusPassword - } - } - } else { - logger.warn("No nexus repository is added; nexusUsername or nexusPassword is null.") - } - } } if (name != "worldedit-fabric") { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa9ed4746..0feda764e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] # Minecraft expectations -fastutil = "8.2.1" -log4j = "2.17.0" -guava = "21.0" -gson = "2.8.0" +fastutil = "8.5.6" +log4j = "2.17.1" +guava = "31.0.1-jre" +gson = "2.8.8" # Platform expectations -paper = "1.17.1-R0.1-SNAPSHOT" +paper = "1.18.1-R0.1-SNAPSHOT" # Plugins vault = "1.7.1" @@ -20,15 +20,14 @@ residence = "4.5._13.1" towny = "0.97.5.0" protocollib = "4.7.0" plotsquaredV6 = "6.2.0" -plotsquaredV4 = "4.514" redprotect = "1.9.6" # Third party flow-math = "1.0.3" -paperlib = "1.0.7" +paperlib = "1.0.8-SNAPSHOT" bstats = "2.2.1" serverlib = "2.3.1" -paster = "1.1.1" +paster = "1.1.3" sparsebitset = "1.2" parallelgzip = "1.0.5" adventure = "4.9.3" @@ -39,7 +38,6 @@ rhino-runtime = "1.7.13" zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs antlr4 = "4.9.3" json-simple = "1.1.1" -paranamer = "2.8" jlibnoise = "1.0.0" jchronic = "0.2.4a" lz4-java = "1.8.0" @@ -81,7 +79,6 @@ towny = { group = "com.github.TownyAdvanced", name = "Towny", version.ref = "tow protocollib = { group = "com.comphenix.protocol", name = "ProtocolLib", version.ref = "protocollib" } plotsquaredV6Bukkit = { group = "com.plotsquared", name = "PlotSquared-Bukkit", version.ref = "plotsquaredV6" } plotsquaredV6Core = { group = "com.plotsquared", name = "PlotSquared-Core", version.ref = "plotsquaredV6" } -plotsquaredV4 = { group = "com.github.intellectualsites.plotsquared", name = "PlotSquared-API", version.ref = "plotsquaredV4" } redprotect = { group = "net.fabiozumbi12", name = "redprotect", version.ref = "redprotect" } # Third Party @@ -104,7 +101,6 @@ zstd = { group = "com.github.luben", name = "zstd-jni", version.ref = "zstd-jni" antlr4 = { group = "org.antlr", name = "antlr4", version.ref = "antlr4" } antlr4Runtime = { group = "org.antlr", name = "antlr4-runtime", version.ref = "antlr4" } jsonSimple = { group = "com.googlecode.json-simple", name = "json-simple", version.ref = "json-simple" } -paranamer = { group = "com.thoughtworks.paranamer", name = "paranamer", version.ref = "paranamer" } jlibnoise = { group = "com.sk89q.lib", name = "jlibnoise", version.ref = "jlibnoise" } jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" } lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" } diff --git a/renovate.json b/renovate.json index b6e9da95a..7da708f2e 100644 --- a/renovate.json +++ b/renovate.json @@ -10,7 +10,6 @@ "mockito-core", "org.antlr", "antlr4-runtime", - "paranamer", "fastutil", "it.unimi.dsi:fastutil", "auto-value-annotations", diff --git a/settings.gradle.kts b/settings.gradle.kts index 284f76861..89dc64163 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,7 @@ include("worldedit-libs") include("worldedit-bukkit:adapters:adapter-legacy") include("worldedit-bukkit:adapters:adapter-1_17_1") +include("worldedit-bukkit:adapters:adapter-1_18") listOf("bukkit", "core", "cli").forEach { include("worldedit-libs:$it") diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts index a6dc955ef..0aa31cc0b 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts @@ -1,21 +1,27 @@ +applyPaperweightAdapterConfiguration() + plugins { java } -applyPaperweightAdapterConfiguration( - "1.17.1-R0.1-20211210.043523-198" -) - repositories { + mavenCentral() maven { name = "PaperMC" url = uri("https://papermc.io/repo/repository/maven-public/") - content { - includeModule("io.papermc", "paperlib") - } } } +java { + toolchain.languageVersion.set(JavaLanguageVersion.of(17)) +} + +configurations.all { + attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) +} + + dependencies { + paperDevBundle("1.17.1-R0.1-20211219.175449-201") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java index 3cc940eb7..f0246debf 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe; +import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -35,8 +36,10 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightFaweAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -53,6 +56,7 @@ import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; @@ -168,11 +172,11 @@ import static com.google.common.base.Preconditions.checkState; public final class PaperweightAdapter implements BukkitImplAdapter { - private final Logger logger = Logger.getLogger(getClass().getCanonicalName()); + private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); - private final Field serverWorldsField; - private final Method getChunkFutureMethod; - private final Field chunkProviderExecutorField; + private final Field worldsField; + private final Method getChunkFutureMainThreadMethod; + private final Field mainThreadProcessorField; private final Watchdog watchdog; // ------------------------------------------------------------------------ @@ -188,18 +192,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData(); + BlockState state = BukkitAdapter.adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + + return state; + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); CraftWorld craftWorld = ((CraftWorld) location.getWorld()); int x = location.getBlockX(); @@ -328,19 +354,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } // Read the NBT data BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readTileEntityIntoTag(te, tag); // Load data + net.minecraft.nbt.CompoundTag tag = te.save(new net.minecraft.nbt.CompoundTag()); //FAWE start - BinaryTag return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); //FAWE end @@ -418,7 +436,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + ); + //FAWE end } @Nullable @@ -500,7 +523,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) worldsField.get(Bukkit.getServer()); map.remove("worldeditregentempworld"); } catch (IllegalAccessException ignored) { } @@ -723,7 +746,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> chunkLoadings = submitChunkLoadTasks(region, serverWorld); BlockableEventLoop executor; try { - executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); + executor = (BlockableEventLoop) mainThreadProcessorField.get(serverWorld.getChunkSource()); } catch (IllegalAccessException e) { throw new IllegalStateException("Couldn't get executor for chunk loading.", e); } @@ -748,8 +771,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter state = BlockStateIdAccess.getBlockStateById(internalId); + BlockStateHolder state = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).adapt(blockData); Objects.requireNonNull(state); BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { @@ -783,7 +807,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -875,7 +899,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { Preconditions.checkNotNull(location); CraftWorld craftWorld = ((CraftWorld) location.getWorld()); @@ -240,19 +261,22 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int y = location.getBlockY(); int z = location.getBlockZ(); - final ServerLevel serverLevel = craftWorld.getHandle(); - LevelChunk levelChunk = serverLevel.getChunk(x >> 4, z >> 4); + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); final BlockPos blockPos = new BlockPos(x, y, z); - org.bukkit.block.Block bukkitBlock = location.getBlock(); - BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } if (state.getBlockType().getMaterial().hasContainer()) { // Read the NBT data - BlockEntity blockEntity = levelChunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - blockEntity.save(tag); // readTileEntityIntoTag - load data - return state.toBaseBlock((CompoundTag) toNative(tag)); + net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); } } @@ -284,7 +308,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity - CompoundTag compoundTag = state instanceof BaseBlock ? state.getNbtData() : null; + CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; if (compoundTag != null || existing instanceof TileEntityBlock) { level.setBlock(blockPos, blockState, 0); // remove tile @@ -293,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements // though we do not do this on the Forge version BlockEntity blockEntity = level.getBlockEntity(blockPos); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(compoundTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); @@ -337,14 +361,15 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundTag tag = (CompoundTag) toNative(minecraftTag); - final Map tags = new HashMap<>(tag.getValue()); - tags.put("Id", new StringTag(id)); - return new CompoundTag(tags); + final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); + final Map tags = new HashMap<>(); + tag.keySet().forEach(key -> tags.put(key, tag.get(key))); + tags.put("Id", StringBinaryTag.of(id)); + return CompoundBinaryTag.from(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -401,7 +426,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 ); - return 0; + return BlockTypesCache.ReservedIDs.AIR; } } } @@ -486,10 +511,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements chunkPacket.setNativePacket(nmsPacket); } try { - FaweCache.IMP.CHUNK_FLAG.get().set(true); + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); entityPlayer.connection.send(nmsPacket); } finally { - FaweCache.IMP.CHUNK_FLAG.get().set(false); + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); } } }); @@ -517,7 +542,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), baseItemStack.getAmount() ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt()))); return CraftItemStack.asCraftMirror(stack); } @@ -579,7 +604,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag()))); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); return weStack; } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java index ba56db4a7..1873a6310 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java @@ -250,7 +250,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess TaskManager.IMP.sync(runnableVal)); + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); } @Override @@ -269,27 +269,17 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); @@ -546,25 +546,30 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } // Biomes - BiomeType[] biomes = set.getBiomes(); + BiomeType[][] biomes = set.getBiomes(); if (biomes != null) { // set biomes ChunkBiomeContainer currentBiomes = nmsChunk.getBiomes(); if (createCopy) { copy.storeBiomes(currentBiomes); } - for (int y = 0, i = 0; y < 64; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, i++) { - final BiomeType biome = biomes[i]; - if (biome != null) { - Biome nmsBiome = - nmsWorld.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).get( - ResourceLocation.tryParse(biome.getId())); - if (nmsBiome == null) { - throw new NullPointerException("BiomeBase null for BiomeType " + biome.getId()); + for (int layer = 0; layer < 16; layer++) { + if (biomes[layer] == null) { + continue; + } + for (int y = 0, i = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, i++) { + final BiomeType biome = biomes[layer][i]; + if (biome != null) { + Biome nmsBiome = + nmsWorld.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).get( + ResourceLocation.tryParse(biome.getId())); + if (nmsBiome == null) { + throw new NullPointerException("BiomeBase null for BiomeType " + biome.getId()); + } + currentBiomes.setBiome(x, (layer << 2) + y, z, nmsBiome); } - currentBiomes.setBiome(x, y, z, nmsBiome); } } } @@ -722,7 +727,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.mustNotSave = false; nmsChunk.markUnsaved(); // send to player - if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { this.send(finalMask, finalLightUpdate); } if (finalizer != null) { @@ -731,7 +736,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc }; } if (syncTasks != null) { - QueueHandler queueHandler = Fawe.get().getQueueHandler(); + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); Runnable[] finalSyncTasks = syncTasks; // Chain the sync tasks and the callback @@ -756,6 +761,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw e; } }; + //noinspection unchecked - required at compile time return (T) (Future) queueHandler.sync(chain); } else { if (callback == null) { @@ -840,16 +846,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc // Section is null, return empty array if (section == null) { data = new char[4096]; - Arrays.fill(data, (char) 1); + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); return data; } if (data != null && data.length != 4096) { data = new char[4096]; - Arrays.fill(data, (char) 1); + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); } - if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) { + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { data = new char[4096]; - Arrays.fill(data, (char) 1); + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); } DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); synchronized (lock) { @@ -874,13 +880,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc for (int i = 0; i < 4096; i++) { char paletteVal = data[i]; char ordinal = adapter.ibdIDToOrdinal(paletteVal); - // Don't read "empty". - data[i] = ordinal == 0 ? 1 : ordinal; + data[i] = ordinal; } return data; } - char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get(); + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); try { if (num_palette != 1) { for (int i = 0; i < num_palette; i++) { @@ -894,18 +899,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc val = ordinal(palette.valueFor(i), adapter); paletteToOrdinal[i] = val; } - // Don't read "empty". - if (val == 0) { - val = 1; - } data[i] = val; } } else { char ordinal = ordinal(palette.valueFor(0), adapter); - // Don't read "empty". - if (ordinal == 0) { - ordinal = 1; - } Arrays.fill(data, ordinal); } } finally { @@ -925,7 +922,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) { if (ibd == null) { - return BlockTypes.AIR.getDefaultState().getOrdinalChar(); + return BlockTypesCache.ReservedIDs.AIR; } else { return adapter.adaptToChar(ibd); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java index 38d54e0ef..b8b791e88 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java @@ -86,7 +86,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final long fieldLockOffset; private static final Field fieldGameEventDispatcherSections; - private static final MethodHandle methodremoveTickingBlockEntity; + private static final MethodHandle methodremoveBlockEntityTicker; private static final Field fieldRemove; @@ -133,7 +133,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { ), BlockPos.class ); removeBlockEntityTicker.setAccessible(true); - methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker); + methodremoveBlockEntityTicker = MethodHandles.lookup().unreflect(removeBlockEntityTicker); fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); @@ -215,7 +215,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { e.printStackTrace(); } } - return TaskManager.IMP.sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); } public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { @@ -247,7 +247,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return; } LevelChunk levelChunk = optional.get(); - TaskManager.IMP.task(() -> { + TaskManager.taskManager().task(() -> { ClientboundLevelChunkPacket chunkPacket = new ClientboundLevelChunkPacket(levelChunk); nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(chunkPacket)); if (lighting) { @@ -283,10 +283,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (set == null) { return newChunkSection(layer); } - final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get(); - final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get(); - final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get(); - final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get(); + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); try { int[] num_palette_buffer = new int[1]; Map ticking_blocks = new HashMap<>(); @@ -303,7 +303,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { int num_palette = num_palette_buffer[0]; // BlockStates int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) { bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry } else { bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries @@ -440,7 +440,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove.set(beacon, true); } } - methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + methodremoveBlockEntityTicker.invoke(levelChunk, beacon.getBlockPos()); } catch (Throwable throwable) { throwable.printStackTrace(); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java index bd8363ece..d51b3a6fc 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java @@ -129,7 +129,7 @@ public class PaperweightStarlightRelighter implements Relighter { while (iterator.hasNext()) { coords.add(new ChunkPos(iterator.nextLong())); } - TaskManager.IMP.task(() -> { + TaskManager.taskManager().task(() -> { // trigger chunk load and apply ticket on main thread List> futures = new ArrayList<>(); for (ChunkPos pos : coords) { @@ -153,9 +153,9 @@ public class PaperweightStarlightRelighter implements Relighter { LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); } // post process chunks on main thread - TaskManager.IMP.task(() -> postProcessChunks(coords)); + TaskManager.taskManager().task(() -> postProcessChunks(coords)); // call callback on our own threads - TaskManager.IMP.async(andThen); + TaskManager.taskManager().async(andThen); } ) ); @@ -184,7 +184,7 @@ public class PaperweightStarlightRelighter implements Relighter { * Also, if chunk packets are sent delayed, we need to do that here */ private void postProcessChunks(Set coords) { - boolean delay = Settings.IMP.LIGHTING.DELAY_PACKET_SENDING; + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; for (ChunkPos pos : coords) { int x = pos.x; int z = pos.z; diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java index 41cc94827..f71a3954e 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java @@ -66,8 +66,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { public double asDouble(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag) { - return ((NumericTag) tag).getAsDouble(); + if (tag instanceof NumericTag numTag) { + return numTag.getAsDouble(); } return 0; } @@ -86,20 +86,19 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { public int asInt(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag) { - return ((NumericTag) tag).getAsInt(); + if (tag instanceof NumericTag numTag) { + return numTag.getAsInt(); } return 0; } public List getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { + if (tag instanceof net.minecraft.nbt.ListTag nbtList) { ArrayList list = new ArrayList<>(); - net.minecraft.nbt.ListTag nbtList = (net.minecraft.nbt.ListTag) tag; for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag) { - list.add(new PaperweightLazyCompoundTag((net.minecraft.nbt.CompoundTag) elem)); + if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { + list.add(new PaperweightLazyCompoundTag(compoundTag)); } else { list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); } @@ -137,8 +136,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { public long asLong(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag) { - return ((NumericTag) tag).getAsLong(); + if (tag instanceof NumericTag numTag) { + return numTag.getAsLong(); } return 0; } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java index 2e16b9f28..12a12d059 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java @@ -90,13 +90,13 @@ public class PaperweightRegen extends Regenerator chunkStati = new LinkedHashMap<>(); @@ -125,8 +125,8 @@ public class PaperweightRegen extends Regenerator levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("worldeditregentempworld", levelStemResourceKey); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; MinecraftServer server = originalServerWorld.getCraftServer().getServer(); @@ -221,7 +221,7 @@ public class PaperweightRegen extends Regenerator) () -> new ServerLevel( + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( server, server.executor, session, @@ -270,8 +270,8 @@ public class PaperweightRegen extends Regenerator { + Fawe.instance().getQueueHandler().sync(() -> { try { freshChunkProvider.close(false); } catch (IOException e) { @@ -348,7 +348,7 @@ public class PaperweightRegen extends Regenerator blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); + TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); } @Override @@ -403,10 +403,10 @@ public class PaperweightRegen extends Regenerator { + Fawe.instance().getQueueHandler().sync(() -> { try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("worldeditregentempworld"); + Map map = (Map) worldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); } catch (IllegalAccessException e) { throw new RuntimeException(e); } @@ -414,15 +414,11 @@ public class PaperweightRegen extends Regenerator getWorldDimKey(org.bukkit.World.Environment env) { - switch (env) { - case NETHER: - return LevelStem.NETHER; - case THE_END: - return LevelStem.END; - case NORMAL: - default: - return LevelStem.OVERWORLD; - } + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; } private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception { diff --git a/worldedit-bukkit/adapters/adapter-1_18/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_18/build.gradle.kts new file mode 100644 index 000000000..e3658659c --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + java +} + +applyPaperweightAdapterConfiguration() + +repositories { + maven { + name = "PaperMC" + url = uri("https://papermc.io/repo/repository/maven-public/") + } +} + +dependencies { + paperDevBundle("1.18.1-R0.1-20211221.093324-19") + compileOnly(libs.paperlib) +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightAdapter.java new file mode 100644 index 000000000..3c08adf0c --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightAdapter.java @@ -0,0 +1,1070 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.PaperweightFaweAdapter; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.ByteBinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; +import com.sk89q.worldedit.util.nbt.EndBinaryTag; +import com.sk89q.worldedit.util.nbt.FloatBinaryTag; +import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.IntBinaryTag; +import com.sk89q.worldedit.util.nbt.ListBinaryTag; +import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; +import com.sk89q.worldedit.util.nbt.LongBinaryTag; +import com.sk89q.worldedit.util.nbt.ShortBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.item.ItemType; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; +import net.minecraft.resources.RegistryReadOps; +import net.minecraft.resources.RegistryWriteOps; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.StringRepresentable; +import net.minecraft.util.thread.BlockableEventLoop; +import net.minecraft.world.Clearable; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World.Environment; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_18_R1.CraftServer; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.generator.ChunkGenerator; +import org.spigotmc.SpigotConfig; +import org.spigotmc.WatchdogThread; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +public final class PaperweightAdapter implements BukkitImplAdapter { + + private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); + + private final Field worldsField; + private final Method getChunkFutureMainThreadMethod; + private final Field mainThreadProcessorField; + private final Watchdog watchdog; + + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + + public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { + // A simple test + CraftServer.class.cast(Bukkit.getServer()); + + int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + if (dataVersion != 2860 && dataVersion != 2865) { + throw new UnsupportedClassVersionError("Not 1.18 or 1.18.1!"); + } + + worldsField = CraftServer.class.getDeclaredField("worlds"); + worldsField.setAccessible(true); + + getChunkFutureMainThreadMethod = ServerChunkCache.class.getDeclaredMethod( + Refraction.pickName("getChunkFutureMainThread", "c"), + int.class, int.class, ChunkStatus.class, boolean.class + ); + getChunkFutureMainThreadMethod.setAccessible(true); + + mainThreadProcessorField = ServerChunkCache.class.getDeclaredField( + Refraction.pickName("mainThreadProcessor", "h") + ); + mainThreadProcessorField.setAccessible(true); + + new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).build(ForkJoinPool.commonPool()); + + Watchdog watchdog; + try { + Class.forName("org.spigotmc.WatchdogThread"); + watchdog = new SpigotWatchdog(); + } catch (ClassNotFoundException | NoSuchFieldException e) { + try { + watchdog = new MojangWatchdog(((CraftServer) Bukkit.getServer()).getServer()); + } catch (NoSuchFieldException ex) { + watchdog = null; + } + } + this.watchdog = watchdog; + + try { + Class.forName("org.spigotmc.SpigotConfig"); + SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false); + } catch (ClassNotFoundException ignored) { + } + } + + @Override + public DataFixer getDataFixer() { + return PaperweightDataConverters.INSTANCE; + } + + /** + * Read the given NBT data into the given tile entity. + * + * @param tileEntity the tile entity + * @param tag the tag + */ + static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) { + tileEntity.load(tag); + tileEntity.setChanged(); + } + + /** + * Get the ID string of the given entity. + * + * @param entity the entity + * @return the entity ID + */ + private static String getEntityId(Entity entity) { + return EntityType.getKey(entity.getType()).toString(); + } + + /** + * Create an entity using the given entity ID. + * + * @param id the entity ID + * @param world the world + * @return an entity or null + */ + @Nullable + private static Entity createEntityFromId(String id, net.minecraft.world.level.Level world) { + return EntityType.byString(id).map(t -> t.create(world)).orElse(null); + } + + /** + * Write the given NBT data into the given entity. + * + * @param entity the entity + * @param tag the tag + */ + private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { + entity.load(tag); + } + + /** + * Write the entity's NBT data to the given tag. + * + * @param entity the entity + * @param tag the tag + */ + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { + entity.save(tag); + } + + private static Block getBlockFromType(BlockType blockType) { + return Registry.BLOCK.get(ResourceLocation.tryParse(blockType.getId())); + } + + private static Item getItemFromType(ItemType itemType) { + return Registry.ITEM.get(ResourceLocation.tryParse(itemType.getId())); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockData data) { + net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); + int combinedId = Block.getId(state); + return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + Block mcBlock = getBlockFromType(state.getBlockType()); + net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); + Map, Object> states = state.getStates(); + newState = applyProperties(mcBlock.getStateDefinition(), newState, states); + final int combinedId = Block.getId(newState); + return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); + } + + @Override + public BlockState getBlock(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData(); + BlockState state = BukkitAdapter.adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + + return state; + } + + @Override + public BaseBlock getFullBlock(Location location) { + BlockState state = getBlock(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + + // Read the NBT data + BlockEntity te = chunk.getBlockEntity(blockPos); + if (te != null) { + net.minecraft.nbt.CompoundTag tag = te.saveWithId(); + //FAWE start - BinaryTag + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + //FAWE end + } + + return state.toBaseBlock(); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightWorldNativeAccess( + this, + new WeakReference<>(((CraftWorld) world).getHandle()) + ); + } + + private static net.minecraft.core.Direction adapt(Direction face) { + switch (face) { + case NORTH: + return net.minecraft.core.Direction.NORTH; + case SOUTH: + return net.minecraft.core.Direction.SOUTH; + case WEST: + return net.minecraft.core.Direction.WEST; + case EAST: + return net.minecraft.core.Direction.EAST; + case DOWN: + return net.minecraft.core.Direction.DOWN; + case UP: + default: + return net.minecraft.core.Direction.UP; + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private net.minecraft.world.level.block.state.BlockState applyProperties( + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states + ) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.world.level.block.state.properties.Property property = + stateContainer.getProperty(state.getKey().getName()); + Comparable value = (Comparable) state.getValue(); + // we may need to adapt this value, depending on the source prop + if (property instanceof DirectionProperty) { + Direction dir = (Direction) value; + value = adapt(dir); + } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); + } + + newState = newState.setValue( + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value + ); + } + return newState; + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, tag); + //FAWE start - BinaryTag + return new BaseEntity( + com.sk89q.worldedit.world.entity.EntityTypes.get(id), + LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + ); + //FAWE end + } + + @Nullable + @Override + public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { + checkNotNull(location); + checkNotNull(state); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + ServerLevel worldServer = craftWorld.getHandle(); + + Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); + + if (createdEntity != null) { + CompoundBinaryTag nativeTag = state.getNbt(); + if (nativeTag != null) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + readTagIntoEntity(tag, createdEntity); + } + + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); + return createdEntity.getBukkitEntity(); + } else { + return null; + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Map> getProperties(BlockType blockType) { + Map> properties = Maps.newTreeMap(String::compareTo); + Block block = getBlockFromType(blockType); + StateDefinition blockStateList = + block.getStateDefinition(); + for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { + Property property; + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + property = new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + property = new DirectionalProperty( + state.getName(), + (List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + property = new EnumProperty( + state.getName(), + (List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + property = new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName()); + } + + properties.put(property.getName(), property); + } + return properties; + } + + @Override + public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + ((CraftPlayer) player).getHandle().networkManager.send(ClientboundBlockEntityDataPacket.create( + new StructureBlockEntity( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + Blocks.STRUCTURE_BLOCK.defaultBlockState() + ), + __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + )); + } + + @Override + public void sendFakeOP(Player player) { + ((CraftPlayer) player).getHandle().networkManager.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle(), (byte) 28 + )); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { + ItemStack stack = new ItemStack(Registry.ITEM.get(ResourceLocation.tryParse(item.getType().getId())), item.getAmount()); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + private final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + + @Override + public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { + CraftWorld craftWorld = (CraftWorld) world; + ServerLevel worldServer = craftWorld.getHandle(); + ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack + ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); + stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); + + PaperweightFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(worldServer); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); + fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch() + ); + + final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); + final net.minecraft.core.Direction enumFacing = adapt(face); + BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); + UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); + InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND); + if (result != InteractionResult.SUCCESS) { + if (worldServer + .getBlockState(blockPos) + .use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace) + .consumesAction()) { + result = InteractionResult.SUCCESS; + } else { + result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); + } + } + + return result == InteractionResult.SUCCESS; + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); + return blockData.canSurvive( + ((CraftWorld) world).getHandle(), + new BlockPos(position.getX(), position.getY(), position.getZ()) + ); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { + try { + doRegen(bukkitWorld, region, extent, options); + } catch (Exception e) { + throw new IllegalStateException("Regen failed.", e); + } + + return true; + } + + private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + Environment env = bukkitWorld.getEnvironment(); + ChunkGenerator gen = bukkitWorld.getGenerator(); + + Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); + ResourceKey worldDimKey = getWorldDimKey(env); + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) { + ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); + PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() + .getWorldData().overworldData(); + WorldGenSettings originalOpts = levelProperties.worldGenSettings(); + + long seed = options.getSeed().orElse(originalWorld.getSeed()); + WorldGenSettings newOpts = options.getSeed().isPresent() + ? replaceSeed(originalWorld, seed, originalOpts) + : originalOpts; + + LevelSettings newWorldSettings = new LevelSettings( + "worldeditregentempworld", + levelProperties.settings.gameType(), + levelProperties.settings.hardcore(), + levelProperties.settings.difficulty(), + levelProperties.settings.allowCommands(), + levelProperties.settings.gameRules(), + levelProperties.settings.getDataPackConfig() + ); + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); + + ServerLevel freshWorld = new ServerLevel( + originalWorld.getServer(), + originalWorld.getServer().executor, + session, newWorldData, + originalWorld.dimension(), + originalWorld.dimensionType(), + new NoOpWorldLoadListener(), + newOpts.dimensions().get(worldDimKey).generator(), + originalWorld.isDebug(), + seed, + ImmutableList.of(), + false, + env, gen, + bukkitWorld.getBiomeProvider() + ); + try { + regenForWorld(region, extent, freshWorld, options); + } finally { + freshWorld.getChunkSource().close(false); + } + } finally { + try { + @SuppressWarnings("unchecked") + Map map = (Map) worldsField.get(Bukkit.getServer()); + map.remove("worldeditregentempworld"); + } catch (IllegalAccessException ignored) { + } + SafeFiles.tryHardToDeleteDir(tempDir); + } + } + + // FAWE start - private -> public static + public static WorldGenSettings replaceSeed(ServerLevel originalWorld, long seed, WorldGenSettings originalOpts) { + // FAWE end + RegistryWriteOps nbtReadRegOps = RegistryWriteOps.create( + NbtOps.INSTANCE, + originalWorld.getServer().registryAccess() + ); + RegistryReadOps nbtRegOps = RegistryReadOps.createAndLoad( + NbtOps.INSTANCE, + originalWorld.getServer().getResourceManager(), + originalWorld.getServer().registryAccess() + ); + Codec dimCodec = WorldGenSettings.CODEC; + return dimCodec + .encodeStart(nbtReadRegOps, originalOpts) + .flatMap(tag -> + dimCodec.parse( + recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>()) + ) + ) + .get() + .map( + l -> l, + error -> { + throw new IllegalStateException("Unable to map GeneratorOptions: " + error.message()); + } + ); + } + + // FAWE start - private -> private static + @SuppressWarnings("unchecked") + private static Dynamic recursivelySetSeed( + // FAWE end + Dynamic dynamic, + long seed, + Set> seen + ) { + if (!seen.add(dynamic)) { + return dynamic; + } + return dynamic.updateMapValues(pair -> { + if (pair.getFirst().asString("").equals("seed")) { + return pair.mapSecond(v -> v.createLong(seed)); + } + if (pair.getSecond().getValue() instanceof net.minecraft.nbt.CompoundTag) { + return pair.mapSecond(v -> recursivelySetSeed((Dynamic) v, seed, seen)); + } + return pair; + }); + } + + private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { + ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome); + if (key == null) { + return null; + } + return BiomeTypes.get(key.toString()); + } + + @SuppressWarnings("unchecked") + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws + WorldEditException { + List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); + BlockableEventLoop executor; + try { + executor = (BlockableEventLoop) mainThreadProcessorField.get(serverWorld.getChunkSource()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Couldn't get executor for chunk loading.", e); + } + executor.managedBlock(() -> { + // bail out early if a future fails + if (chunkLoadings.stream().anyMatch(ftr -> + ftr.isDone() && Futures.getUnchecked(ftr) == null + )) { + return false; + } + return chunkLoadings.stream().allMatch(CompletableFuture::isDone); + }); + Map chunks = new HashMap<>(); + for (CompletableFuture future : chunkLoadings) { + @Nullable + ChunkAccess chunk = future.getNow(null); + checkState(chunk != null, "Failed to generate a chunk, regen failed."); + chunks.put(chunk.getPos(), chunk); + } + + for (BlockVector3 vec : region) { + BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); + ChunkAccess chunk = chunks.get(new ChunkPos(pos)); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); + BlockStateHolder state = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()).adapt(blockData); + Objects.requireNonNull(state); + BlockEntity blockEntity = chunk.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + //FAWE start - BinaryTag + state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + //FAWE end + } + extent.setBlock(vec, state.toBaseBlock()); + if (options.shouldRegenBiomes()) { + PalettedContainer biomeIndex = chunk.getSection(chunk.getSectionIndex(vec.getBlockY())) + .getBiomes(); + Biome origBiome = biomeIndex.get(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); + } + } + } + } + + @SuppressWarnings("unchecked") + private List> submitChunkLoadTasks(Region region, ServerLevel serverWorld) { + ServerChunkCache chunkManager = serverWorld.getChunkSource(); + List> chunkLoadings = new ArrayList<>(); + // Pre-gen all the chunks + for (BlockVector2 chunk : region.getChunks()) { + try { + //noinspection unchecked + chunkLoadings.add( + ((CompletableFuture>) + getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) + ); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't load chunk for regen.", e); + } + } + return chunkLoadings; + } + + private ResourceKey getWorldDimKey(Environment env) { + switch (env) { + case NETHER: + return LevelStem.NETHER; + case THE_END: + return LevelStem.END; + case NORMAL: + default: + return LevelStem.OVERWORLD; + } + } + + private static final Set SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE + ); + + @Override + public Set getSupportedSideEffects() { + return SUPPORTED_SIDE_EFFECTS; + } + + @Override + public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + if (entity instanceof Clearable) { + ((Clearable) entity).clearContent(); + return true; + } + return false; + } + + // ------------------------------------------------------------------------ + // Code that is less likely to break + // ------------------------------------------------------------------------ + + /** + * Converts from a non-native NMS NBT structure to a native WorldEdit NBT + * structure. + * + * @param foreign non-native NMS NBT structure + * @return native WorldEdit NBT structure + */ + //FAWE start - BinaryTag + @Override + public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof net.minecraft.nbt.CompoundTag) { + Map values = new HashMap<>(); + Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); + + for (String str : foreignKeys) { + net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); + values.put(str, toNativeBinary(base)); + } + return CompoundBinaryTag.from(values); + } else if (foreign instanceof net.minecraft.nbt.ByteTag) { + return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { + return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { + return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + } else if (foreign instanceof net.minecraft.nbt.FloatTag) { + return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + } else if (foreign instanceof net.minecraft.nbt.IntTag) { + return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { + return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { + return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + } else if (foreign instanceof net.minecraft.nbt.ListTag) { + try { + return toNativeList((net.minecraft.nbt.ListTag) foreign); + } catch (Throwable e) { + LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); + return ListBinaryTag.empty(); + } + } else if (foreign instanceof net.minecraft.nbt.LongTag) { + return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + } else if (foreign instanceof net.minecraft.nbt.ShortTag) { + return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + } else if (foreign instanceof net.minecraft.nbt.StringTag) { + return StringBinaryTag.of(foreign.getAsString()); + } else if (foreign instanceof net.minecraft.nbt.EndTag) { + return EndBinaryTag.get(); + } else { + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + } + } + + /** + * Convert a foreign NBT list tag into a native WorldEdit one. + * + * @param foreign the foreign tag + * @return the converted tag + * @throws SecurityException on error + * @throws IllegalArgumentException on error + */ + private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + ListBinaryTag.Builder values = ListBinaryTag.builder(); + + for (net.minecraft.nbt.Tag tag : foreign) { + values.add(toNativeBinary(tag)); + } + + return values.build(); + } + + /** + * Converts a WorldEdit-native NBT structure to a NMS structure. + * + * @param foreign structure to convert + * @return non-native structure + */ + @Override + public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + if (foreign == null) { + return null; + } + if (foreign instanceof CompoundBinaryTag) { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + for (String key : ((CompoundBinaryTag) foreign).keySet()) { + tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + } + return tag; + } else if (foreign instanceof ByteBinaryTag) { + return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); + } else if (foreign instanceof ByteArrayBinaryTag) { + return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); + } else if (foreign instanceof DoubleBinaryTag) { + return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); + } else if (foreign instanceof FloatBinaryTag) { + return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); + } else if (foreign instanceof IntBinaryTag) { + return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); + } else if (foreign instanceof IntArrayBinaryTag) { + return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); + } else if (foreign instanceof LongArrayBinaryTag) { + return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); + } else if (foreign instanceof ListBinaryTag) { + net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); + ListBinaryTag foreignList = (ListBinaryTag) foreign; + for (BinaryTag t : foreignList) { + tag.add(fromNativeBinary(t)); + } + return tag; + } else if (foreign instanceof LongBinaryTag) { + return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); + } else if (foreign instanceof ShortBinaryTag) { + return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); + } else if (foreign instanceof StringBinaryTag) { + return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); + } else if (foreign instanceof EndBinaryTag) { + return net.minecraft.nbt.EndTag.INSTANCE; + } else { + throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); + } + } + //FAWE end + + @Override + public boolean supportsWatchdog() { + return watchdog != null; + } + + @Override + public void tickWatchdog() { + watchdog.tick(); + } + + private class SpigotWatchdog implements Watchdog { + + private final Field instanceField; + private final Field lastTickField; + + SpigotWatchdog() throws NoSuchFieldException { + Field instanceField = WatchdogThread.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + this.instanceField = instanceField; + + Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); + lastTickField.setAccessible(true); + this.lastTickField = lastTickField; + } + + @Override + public void tick() { + try { + WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); + if ((long) lastTickField.get(instance) != 0) { + WatchdogThread.tick(); + } + } catch (IllegalAccessException e) { + LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); + } + } + + } + + private static class MojangWatchdog implements Watchdog { + + private final DedicatedServer server; + private final Field tickField; + + MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { + this.server = server; + Field tickField = MinecraftServer.class.getDeclaredField( + Refraction.pickName("nextTickTime", "ao") + ); + tickField.setAccessible(true); + this.tickField = tickField; + } + + @Override + public void tick() { + try { + tickField.set(server, Util.getMillis()); + } catch (IllegalAccessException ignored) { + } + } + + } + + private static class NoOpWorldLoadListener implements ChunkProgressListener { + + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { + } + + @Override + public void start() { + } + + @Override + public void stop() { + } + + @Override + public void setChunkRadius(int radius) { + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightDataConverters.java new file mode 100644 index 000000000..a445ed37d --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightDataConverters.java @@ -0,0 +1,2961 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.serialization.Dynamic; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.core.Direction; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.StringUtil; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.DyeColor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +/** + * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) + *

+ * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy + * which is safer, faster and cleaner code. + *

+ * The pre DFU code did not fail when the Source version was unknown. + *

+ * This class also provides util methods for converting compounds to wrap the update call to + * receive the source version in the compound + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + //FAWE start - BinaryTag + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundBinaryTag) original, srcVer); + } else if (type == FixTypes.BLOCK_STATE) { + return (T) fixBlockState((String) original, srcVer); + } else if (type == FixTypes.ITEM_TYPE) { + return (T) fixItemType((String) original, srcVer); + } else if (type == FixTypes.BIOME) { + return (T) fixBiome((String) original, srcVer); + } + return original; + } + + private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + + private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + } + //FAWE end + + private String fixBlockState(String blockState, int srcVer) { + net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update( + References.BLOCK_STATE, + dynamic, + srcVer, + DATA_VERSION + ).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(net.minecraft.nbt.CompoundTag tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props + .getAllKeys() + .stream() + .map(k -> k + "=" + props.getString(k).replace("\"", "")) + .collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static net.minecraft.nbt.CompoundTag stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + net.minecraft.nbt.CompoundTag propTag = new net.minecraft.nbt.CompoundTag(); + String props = blockState.substring(propIdx + 1, blockState.length() - 1); + String[] propArr = props.split(","); + for (String pair : propArr) { + final String[] split = pair.split("="); + propTag.putString(split[0], split[1]); + } + tag.put("Properties", propTag); + } + return tag; + } + + private String fixBiome(String key, int srcVer) { + return fixName(key, srcVer, References.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, References.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); + } + + private final PaperweightAdapter adapter; + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + static PaperweightDataConverters INSTANCE; + + private final Map> converters = new EnumMap<>(LegacyType.class); + private final Map> inspectors = new EnumMap<>(LegacyType.class); + + // Set on build + private DataFixer fixer; + private static final Map DFU_TO_LEGACY = new HashMap<>(); + + public enum LegacyType { + LEVEL(References.LEVEL), + PLAYER(References.PLAYER), + CHUNK(References.CHUNK), + BLOCK_ENTITY(References.BLOCK_ENTITY), + ENTITY(References.ENTITY), + ITEM_INSTANCE(References.ITEM_STACK), + OPTIONS(References.OPTIONS), + STRUCTURE(References.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + this.adapter = adapter; + registerConverters(); + registerInspectors(); + } + + + // Called after fixers are built and ready for FIXING + @Override + public DataFixer build(final Executor executor) { + return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); + } + + @SuppressWarnings("unchecked") + private class WrappedDataFixer implements DataFixer { + + private final DataFixer realFixer; + + WrappedDataFixer(DataFixer realFixer) { + this.realFixer = realFixer; + } + + @Override + public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { + LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); + if (sourceVer < LEGACY_VERSION && legacyType != null) { + net.minecraft.nbt.CompoundTag cmp = (net.minecraft.nbt.CompoundTag) dynamic.getValue(); + int desiredVersion = Math.min(targetVer, LEGACY_VERSION); + + cmp = convert(legacyType, cmp, sourceVer, desiredVersion); + sourceVer = desiredVersion; + dynamic = new Dynamic(OPS_NBT, cmp); + } + return realFixer.update(type, dynamic, sourceVer, targetVer); + } + + private net.minecraft.nbt.CompoundTag convert( + LegacyType type, + net.minecraft.nbt.CompoundTag cmp, + int sourceVer, + int desiredVersion + ) { + List converters = PaperweightDataConverters.this.converters.get(type); + if (converters != null && !converters.isEmpty()) { + for (DataConverter converter : converters) { + int dataVersion = converter.getDataVersion(); + if (dataVersion > sourceVer && dataVersion <= desiredVersion) { + cmp = converter.convert(cmp); + } + } + } + + List inspectors = PaperweightDataConverters.this.inspectors.get(type); + if (inspectors != null && !inspectors.isEmpty()) { + for (DataInspector inspector : inspectors) { + cmp = inspector.inspect(cmp, sourceVer, desiredVersion); + } + } + + return cmp; + } + + @Override + public Schema getSchema(int i) { + return realFixer.getSchema(i); + } + + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { + return convert(type.getDFUType(), cmp); + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static net.minecraft.nbt.CompoundTag convert( + LegacyType type, + net.minecraft.nbt.CompoundTag cmp, + int sourceVer, + int targetVer + ) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp) { + int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static net.minecraft.nbt.CompoundTag convert( + TypeReference type, + net.minecraft.nbt.CompoundTag cmp, + int sourceVer, + int targetVer + ) { + if (sourceVer >= targetVer) { + return cmp; + } + return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer + .update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer) + .getValue(); + } + + + public interface DataInspector { + + net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer); + + } + + public interface DataConverter { + + int getDataVersion(); + + net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); + + } + + + private void registerInspector(LegacyType type, DataInspector inspector) { + this.inspectors.computeIfAbsent(type, k -> new ArrayList<>()).add(inspector); + } + + private void registerConverter(LegacyType type, DataConverter converter) { + int version = converter.getDataVersion(); + + List list = this.converters.computeIfAbsent(type, k -> new ArrayList<>()); + if (!list.isEmpty() && list.get(list.size() - 1).getDataVersion() > version) { + for (int j = 0; j < list.size(); ++j) { + if (list.get(j).getDataVersion() > version) { + list.add(j, converter); + break; + } + } + } else { + list.add(converter); + } + } + + private void registerInspectors() { + registerEntityItemList("EntityHorseDonkey", "SaddleItem", "Items"); + registerEntityItemList("EntityHorseMule", "Items"); + registerEntityItemList("EntityMinecartChest", "Items"); + registerEntityItemList("EntityMinecartHopper", "Items"); + registerEntityItemList("EntityVillager", "Inventory"); + registerEntityItemListEquipment("EntityArmorStand"); + registerEntityItemListEquipment("EntityBat"); + registerEntityItemListEquipment("EntityBlaze"); + registerEntityItemListEquipment("EntityCaveSpider"); + registerEntityItemListEquipment("EntityChicken"); + registerEntityItemListEquipment("EntityCow"); + registerEntityItemListEquipment("EntityCreeper"); + registerEntityItemListEquipment("EntityEnderDragon"); + registerEntityItemListEquipment("EntityEnderman"); + registerEntityItemListEquipment("EntityEndermite"); + registerEntityItemListEquipment("EntityEvoker"); + registerEntityItemListEquipment("EntityGhast"); + registerEntityItemListEquipment("EntityGiantZombie"); + registerEntityItemListEquipment("EntityGuardian"); + registerEntityItemListEquipment("EntityGuardianElder"); + registerEntityItemListEquipment("EntityHorse"); + registerEntityItemListEquipment("EntityHorseDonkey"); + registerEntityItemListEquipment("EntityHorseMule"); + registerEntityItemListEquipment("EntityHorseSkeleton"); + registerEntityItemListEquipment("EntityHorseZombie"); + registerEntityItemListEquipment("EntityIronGolem"); + registerEntityItemListEquipment("EntityMagmaCube"); + registerEntityItemListEquipment("EntityMushroomCow"); + registerEntityItemListEquipment("EntityOcelot"); + registerEntityItemListEquipment("EntityPig"); + registerEntityItemListEquipment("EntityPigZombie"); + registerEntityItemListEquipment("EntityRabbit"); + registerEntityItemListEquipment("EntitySheep"); + registerEntityItemListEquipment("EntityShulker"); + registerEntityItemListEquipment("EntitySilverfish"); + registerEntityItemListEquipment("EntitySkeleton"); + registerEntityItemListEquipment("EntitySkeletonStray"); + registerEntityItemListEquipment("EntitySkeletonWither"); + registerEntityItemListEquipment("EntitySlime"); + registerEntityItemListEquipment("EntitySnowman"); + registerEntityItemListEquipment("EntitySpider"); + registerEntityItemListEquipment("EntitySquid"); + registerEntityItemListEquipment("EntityVex"); + registerEntityItemListEquipment("EntityVillager"); + registerEntityItemListEquipment("EntityVindicator"); + registerEntityItemListEquipment("EntityWitch"); + registerEntityItemListEquipment("EntityWither"); + registerEntityItemListEquipment("EntityWolf"); + registerEntityItemListEquipment("EntityZombie"); + registerEntityItemListEquipment("EntityZombieHusk"); + registerEntityItemListEquipment("EntityZombieVillager"); + registerEntityItemSingle("EntityFireworks", "FireworksItem"); + registerEntityItemSingle("EntityHorse", "ArmorItem"); + registerEntityItemSingle("EntityHorse", "SaddleItem"); + registerEntityItemSingle("EntityHorseMule", "SaddleItem"); + registerEntityItemSingle("EntityHorseSkeleton", "SaddleItem"); + registerEntityItemSingle("EntityHorseZombie", "SaddleItem"); + registerEntityItemSingle("EntityItem", "Item"); + registerEntityItemSingle("EntityItemFrame", "Item"); + registerEntityItemSingle("EntityPotion", "Potion"); + + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItem("TileEntityRecordPlayer", "RecordItem")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityBrewingStand", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityChest", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDispenser", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDropper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityFurnace", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityHopper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityShulkerBox", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorMobSpawnerMobs()); + registerInspector(LegacyType.CHUNK, new DataInspectorChunks()); + registerInspector(LegacyType.ENTITY, new DataInspectorCommandBlock()); + registerInspector(LegacyType.ENTITY, new DataInspectorEntityPassengers()); + registerInspector(LegacyType.ENTITY, new DataInspectorMobSpawnerMinecart()); + registerInspector(LegacyType.ENTITY, new DataInspectorVillagers()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorBlockEntity()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorEntity()); + registerInspector(LegacyType.LEVEL, new DataInspectorLevelPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayerVehicle()); + registerInspector(LegacyType.STRUCTURE, new DataInspectorStructure()); + } + + private void registerConverters() { + registerConverter(LegacyType.ENTITY, new DataConverterEquipment()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterSignText()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterMaterialId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterSpawnEgg()); + registerConverter(LegacyType.ENTITY, new DataConverterMinecart()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterMobSpawner()); + registerConverter(LegacyType.ENTITY, new DataConverterUUID()); + registerConverter(LegacyType.ENTITY, new DataConverterHealth()); + registerConverter(LegacyType.ENTITY, new DataConverterSaddle()); + registerConverter(LegacyType.ENTITY, new DataConverterHanging()); + registerConverter(LegacyType.ENTITY, new DataConverterDropChances()); + registerConverter(LegacyType.ENTITY, new DataConverterRiding()); + registerConverter(LegacyType.ENTITY, new DataConverterArmorStand()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBook()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterCookedFish()); + registerConverter(LegacyType.ENTITY, new DataConverterZombie()); + registerConverter(LegacyType.OPTIONS, new DataConverterVBO()); + registerConverter(LegacyType.ENTITY, new DataConverterGuardian()); + registerConverter(LegacyType.ENTITY, new DataConverterSkeleton()); + registerConverter(LegacyType.ENTITY, new DataConverterZombieType()); + registerConverter(LegacyType.ENTITY, new DataConverterHorse()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterTileEntity()); + registerConverter(LegacyType.ENTITY, new DataConverterEntity()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBanner()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionWater()); + registerConverter(LegacyType.ENTITY, new DataConverterShulker()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterShulkerBoxItem()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterShulkerBoxBlock()); + registerConverter(LegacyType.OPTIONS, new DataConverterLang()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterTotem()); + registerConverter(LegacyType.CHUNK, new DataConverterBedBlock()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBedItem()); + } + + private void registerEntityItemList(String type, String... keys) { + registerInspector(LegacyType.ENTITY, new DataInspectorItemList(type, keys)); + } + + private void registerEntityItemSingle(String type, String key) { + registerInspector(LegacyType.ENTITY, new DataInspectorItem(type, key)); + } + + private void registerEntityItemListEquipment(String type) { + registerEntityItemList(type, "ArmorItems", "HandItems"); + } + + private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); + + static { + final Map map = OLD_ID_TO_KEY_MAP; + map.put("EntityItem", new ResourceLocation("item")); + map.put("EntityExperienceOrb", new ResourceLocation("xp_orb")); + map.put("EntityAreaEffectCloud", new ResourceLocation("area_effect_cloud")); + map.put("EntityGuardianElder", new ResourceLocation("elder_guardian")); + map.put("EntitySkeletonWither", new ResourceLocation("wither_skeleton")); + map.put("EntitySkeletonStray", new ResourceLocation("stray")); + map.put("EntityEgg", new ResourceLocation("egg")); + map.put("EntityLeash", new ResourceLocation("leash_knot")); + map.put("EntityPainting", new ResourceLocation("painting")); + map.put("EntityTippedArrow", new ResourceLocation("arrow")); + map.put("EntitySnowball", new ResourceLocation("snowball")); + map.put("EntityLargeFireball", new ResourceLocation("fireball")); + map.put("EntitySmallFireball", new ResourceLocation("small_fireball")); + map.put("EntityEnderPearl", new ResourceLocation("ender_pearl")); + map.put("EntityEnderSignal", new ResourceLocation("eye_of_ender_signal")); + map.put("EntityPotion", new ResourceLocation("potion")); + map.put("EntityThrownExpBottle", new ResourceLocation("xp_bottle")); + map.put("EntityItemFrame", new ResourceLocation("item_frame")); + map.put("EntityWitherSkull", new ResourceLocation("wither_skull")); + map.put("EntityTNTPrimed", new ResourceLocation("tnt")); + map.put("EntityFallingBlock", new ResourceLocation("falling_block")); + map.put("EntityFireworks", new ResourceLocation("fireworks_rocket")); + map.put("EntityZombieHusk", new ResourceLocation("husk")); + map.put("EntitySpectralArrow", new ResourceLocation("spectral_arrow")); + map.put("EntityShulkerBullet", new ResourceLocation("shulker_bullet")); + map.put("EntityDragonFireball", new ResourceLocation("dragon_fireball")); + map.put("EntityZombieVillager", new ResourceLocation("zombie_villager")); + map.put("EntityHorseSkeleton", new ResourceLocation("skeleton_horse")); + map.put("EntityHorseZombie", new ResourceLocation("zombie_horse")); + map.put("EntityArmorStand", new ResourceLocation("armor_stand")); + map.put("EntityHorseDonkey", new ResourceLocation("donkey")); + map.put("EntityHorseMule", new ResourceLocation("mule")); + map.put("EntityEvokerFangs", new ResourceLocation("evocation_fangs")); + map.put("EntityEvoker", new ResourceLocation("evocation_illager")); + map.put("EntityVex", new ResourceLocation("vex")); + map.put("EntityVindicator", new ResourceLocation("vindication_illager")); + map.put("EntityIllagerIllusioner", new ResourceLocation("illusion_illager")); + map.put("EntityMinecartCommandBlock", new ResourceLocation("commandblock_minecart")); + map.put("EntityBoat", new ResourceLocation("boat")); + map.put("EntityMinecartRideable", new ResourceLocation("minecart")); + map.put("EntityMinecartChest", new ResourceLocation("chest_minecart")); + map.put("EntityMinecartFurnace", new ResourceLocation("furnace_minecart")); + map.put("EntityMinecartTNT", new ResourceLocation("tnt_minecart")); + map.put("EntityMinecartHopper", new ResourceLocation("hopper_minecart")); + map.put("EntityMinecartMobSpawner", new ResourceLocation("spawner_minecart")); + map.put("EntityCreeper", new ResourceLocation("creeper")); + map.put("EntitySkeleton", new ResourceLocation("skeleton")); + map.put("EntitySpider", new ResourceLocation("spider")); + map.put("EntityGiantZombie", new ResourceLocation("giant")); + map.put("EntityZombie", new ResourceLocation("zombie")); + map.put("EntitySlime", new ResourceLocation("slime")); + map.put("EntityGhast", new ResourceLocation("ghast")); + map.put("EntityPigZombie", new ResourceLocation("zombie_pigman")); + map.put("EntityEnderman", new ResourceLocation("enderman")); + map.put("EntityCaveSpider", new ResourceLocation("cave_spider")); + map.put("EntitySilverfish", new ResourceLocation("silverfish")); + map.put("EntityBlaze", new ResourceLocation("blaze")); + map.put("EntityMagmaCube", new ResourceLocation("magma_cube")); + map.put("EntityEnderDragon", new ResourceLocation("ender_dragon")); + map.put("EntityWither", new ResourceLocation("wither")); + map.put("EntityBat", new ResourceLocation("bat")); + map.put("EntityWitch", new ResourceLocation("witch")); + map.put("EntityEndermite", new ResourceLocation("endermite")); + map.put("EntityGuardian", new ResourceLocation("guardian")); + map.put("EntityShulker", new ResourceLocation("shulker")); + map.put("EntityPig", new ResourceLocation("pig")); + map.put("EntitySheep", new ResourceLocation("sheep")); + map.put("EntityCow", new ResourceLocation("cow")); + map.put("EntityChicken", new ResourceLocation("chicken")); + map.put("EntitySquid", new ResourceLocation("squid")); + map.put("EntityWolf", new ResourceLocation("wolf")); + map.put("EntityMushroomCow", new ResourceLocation("mooshroom")); + map.put("EntitySnowman", new ResourceLocation("snowman")); + map.put("EntityOcelot", new ResourceLocation("ocelot")); + map.put("EntityIronGolem", new ResourceLocation("villager_golem")); + map.put("EntityHorse", new ResourceLocation("horse")); + map.put("EntityRabbit", new ResourceLocation("rabbit")); + map.put("EntityPolarBear", new ResourceLocation("polar_bear")); + map.put("EntityLlama", new ResourceLocation("llama")); + map.put("EntityLlamaSpit", new ResourceLocation("llama_spit")); + map.put("EntityParrot", new ResourceLocation("parrot")); + map.put("EntityVillager", new ResourceLocation("villager")); + map.put("EntityEnderCrystal", new ResourceLocation("ender_crystal")); + map.put("TileEntityFurnace", new ResourceLocation("furnace")); + map.put("TileEntityChest", new ResourceLocation("chest")); + map.put("TileEntityEnderChest", new ResourceLocation("ender_chest")); + map.put("TileEntityRecordPlayer", new ResourceLocation("jukebox")); + map.put("TileEntityDispenser", new ResourceLocation("dispenser")); + map.put("TileEntityDropper", new ResourceLocation("dropper")); + map.put("TileEntitySign", new ResourceLocation("sign")); + map.put("TileEntityMobSpawner", new ResourceLocation("mob_spawner")); + map.put("TileEntityNote", new ResourceLocation("noteblock")); + map.put("TileEntityPiston", new ResourceLocation("piston")); + map.put("TileEntityBrewingStand", new ResourceLocation("brewing_stand")); + map.put("TileEntityEnchantTable", new ResourceLocation("enchanting_table")); + map.put("TileEntityEnderPortal", new ResourceLocation("end_portal")); + map.put("TileEntityBeacon", new ResourceLocation("beacon")); + map.put("TileEntitySkull", new ResourceLocation("skull")); + map.put("TileEntityLightDetector", new ResourceLocation("daylight_detector")); + map.put("TileEntityHopper", new ResourceLocation("hopper")); + map.put("TileEntityComparator", new ResourceLocation("comparator")); + map.put("TileEntityFlowerPot", new ResourceLocation("flower_pot")); + map.put("TileEntityBanner", new ResourceLocation("banner")); + map.put("TileEntityStructure", new ResourceLocation("structure_block")); + map.put("TileEntityEndGateway", new ResourceLocation("end_gateway")); + map.put("TileEntityCommand", new ResourceLocation("command_block")); + map.put("TileEntityShulkerBox", new ResourceLocation("shulker_box")); + map.put("TileEntityBed", new ResourceLocation("bed")); + } + + private static ResourceLocation getKey(String type) { + final ResourceLocation key = OLD_ID_TO_KEY_MAP.get(type); + if (key == null) { + throw new IllegalArgumentException("Unknown mapping for " + type); + } + return key; + } + + private static void convertCompound( + LegacyType type, + net.minecraft.nbt.CompoundTag cmp, + String key, + int sourceVer, + int targetVer + ) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() { + } + + public int getDataVersion() { + return 100; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); + net.minecraft.nbt.ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1.add(nbttaglist.get(1)); + nbttaglist1.add(nbttaglist.get(2)); + nbttaglist1.add(nbttaglist.get(3)); + nbttaglist1.add(nbttaglist.get(4)); + cmp.put("ArmorItems", nbttaglist1); + } + + cmp.remove("Equipment"); + if (cmp.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + net.minecraft.nbt.ListTag nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new net.minecraft.nbt.ListTag(); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); + nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(4))); + cmp.put("ArmorDropChances", nbttaglist2); + } + + cmp.remove("DropChances"); + } + + return cmp; + } + + } + + private static class DataInspectorBlockEntity implements DataInspector { + + private static final Map b = Maps.newHashMap(); + private static final Map c = Maps.newHashMap(); + + DataInspectorBlockEntity() { + } + + @Nullable + private static String convertEntityId(int i, String s) { + String key = new ResourceLocation(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + String s = cmp.getString("id"); + String s1 = convertEntityId(sourceVer, s); + boolean flag; + + if (s1 == null) { + // CraftBukkit - Remove unnecessary warning (occurs when deserializing a Shulker Box item) + // DataInspectorBlockEntity.a.warn("Unable to resolve BlockEntity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.contains("id"); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + static { + Map map = DataInspectorBlockEntity.b; + + map.put("minecraft:furnace", "Furnace"); + map.put("minecraft:lit_furnace", "Furnace"); + map.put("minecraft:chest", "Chest"); + map.put("minecraft:trapped_chest", "Chest"); + map.put("minecraft:ender_chest", "EnderChest"); + map.put("minecraft:jukebox", "RecordPlayer"); + map.put("minecraft:dispenser", "Trap"); + map.put("minecraft:dropper", "Dropper"); + map.put("minecraft:sign", "Sign"); + map.put("minecraft:mob_spawner", "MobSpawner"); + map.put("minecraft:noteblock", "Music"); + map.put("minecraft:brewing_stand", "Cauldron"); + map.put("minecraft:enhanting_table", "EnchantTable"); + map.put("minecraft:command_block", "CommandBlock"); + map.put("minecraft:beacon", "Beacon"); + map.put("minecraft:skull", "Skull"); + map.put("minecraft:daylight_detector", "DLDetector"); + map.put("minecraft:hopper", "Hopper"); + map.put("minecraft:banner", "Banner"); + map.put("minecraft:flower_pot", "FlowerPot"); + map.put("minecraft:repeating_command_block", "CommandBlock"); + map.put("minecraft:chain_command_block", "CommandBlock"); + map.put("minecraft:standing_sign", "Sign"); + map.put("minecraft:wall_sign", "Sign"); + map.put("minecraft:piston_head", "Piston"); + map.put("minecraft:daylight_detector_inverted", "DLDetector"); + map.put("minecraft:unpowered_comparator", "Comparator"); + map.put("minecraft:powered_comparator", "Comparator"); + map.put("minecraft:wall_banner", "Banner"); + map.put("minecraft:standing_banner", "Banner"); + map.put("minecraft:structure_block", "Structure"); + map.put("minecraft:end_portal", "Airportal"); + map.put("minecraft:end_gateway", "EndGateway"); + map.put("minecraft:shield", "Shield"); + map = DataInspectorBlockEntity.c; + map.put("minecraft:furnace", "minecraft:furnace"); + map.put("minecraft:lit_furnace", "minecraft:furnace"); + map.put("minecraft:chest", "minecraft:chest"); + map.put("minecraft:trapped_chest", "minecraft:chest"); + map.put("minecraft:ender_chest", "minecraft:enderchest"); + map.put("minecraft:jukebox", "minecraft:jukebox"); + map.put("minecraft:dispenser", "minecraft:dispenser"); + map.put("minecraft:dropper", "minecraft:dropper"); + map.put("minecraft:sign", "minecraft:sign"); + map.put("minecraft:mob_spawner", "minecraft:mob_spawner"); + map.put("minecraft:noteblock", "minecraft:noteblock"); + map.put("minecraft:brewing_stand", "minecraft:brewing_stand"); + map.put("minecraft:enhanting_table", "minecraft:enchanting_table"); + map.put("minecraft:command_block", "minecraft:command_block"); + map.put("minecraft:beacon", "minecraft:beacon"); + map.put("minecraft:skull", "minecraft:skull"); + map.put("minecraft:daylight_detector", "minecraft:daylight_detector"); + map.put("minecraft:hopper", "minecraft:hopper"); + map.put("minecraft:banner", "minecraft:banner"); + map.put("minecraft:flower_pot", "minecraft:flower_pot"); + map.put("minecraft:repeating_command_block", "minecraft:command_block"); + map.put("minecraft:chain_command_block", "minecraft:command_block"); + map.put("minecraft:shulker_box", "minecraft:shulker_box"); + map.put("minecraft:white_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:green_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:red_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:black_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:bed", "minecraft:bed"); + map.put("minecraft:standing_sign", "minecraft:sign"); + map.put("minecraft:wall_sign", "minecraft:sign"); + map.put("minecraft:piston_head", "minecraft:piston"); + map.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); + map.put("minecraft:unpowered_comparator", "minecraft:comparator"); + map.put("minecraft:powered_comparator", "minecraft:comparator"); + map.put("minecraft:wall_banner", "minecraft:banner"); + map.put("minecraft:standing_banner", "minecraft:banner"); + map.put("minecraft:structure_block", "minecraft:structure_block"); + map.put("minecraft:end_portal", "minecraft:end_portal"); + map.put("minecraft:end_gateway", "minecraft:end_gateway"); + map.put("minecraft:shield", "minecraft:shield"); + } + } + + private static class DataInspectorEntity implements DataInspector { + + private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class); + + DataInspectorEntity() { + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + String s = cmp.getString("id"); + String s1; + + if ("minecraft:armor_stand".equals(s)) { + s1 = sourceVer < 515 ? "ArmorStand" : "minecraft:armor_stand"; + } else { + if (!"minecraft:spawn_egg".equals(s)) { + return cmp; + } + + s1 = nbttagcompound2.getString("id"); + } + + boolean flag; + + flag = !nbttagcompound2.contains("id", 8); + nbttagcompound2.putString("id", s1); + + convert(LegacyType.ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + + } + + + private abstract static class DataInspectorTagged implements DataInspector { + + private final ResourceLocation key; + + DataInspectorTagged(String type) { + this.key = getKey(type); + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract net.minecraft.nbt.CompoundTag inspectChecked( + net.minecraft.nbt.CompoundTag nbttagcompound, + int sourceVer, + int targetVer + ); + + } + + private static class DataInspectorItemList extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItemList(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + PaperweightDataConverters.convertItems(nbttagcompound, s, sourceVer, targetVer); + } + + return nbttagcompound; + } + + } + + private static class DataInspectorItem extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItem(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + PaperweightDataConverters.convertItem(nbttagcompound, key, sourceVer, targetVer); + } + + return nbttagcompound; + } + + } + + private static class DataConverterMaterialId implements DataConverter { + + private static final String[] materials = new String[2268]; + + DataConverterMaterialId() { + } + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("id", 99)) { + short short0 = cmp.getShort("id"); + + if (short0 > 0 && short0 < materials.length && materials[short0] != null) { + cmp.putString("id", materials[short0]); + } + } + + return cmp; + } + + static { + materials[1] = "minecraft:stone"; + materials[2] = "minecraft:grass"; + materials[3] = "minecraft:dirt"; + materials[4] = "minecraft:cobblestone"; + materials[5] = "minecraft:planks"; + materials[6] = "minecraft:sapling"; + materials[7] = "minecraft:bedrock"; + materials[8] = "minecraft:flowing_water"; + materials[9] = "minecraft:water"; + materials[10] = "minecraft:flowing_lava"; + materials[11] = "minecraft:lava"; + materials[12] = "minecraft:sand"; + materials[13] = "minecraft:gravel"; + materials[14] = "minecraft:gold_ore"; + materials[15] = "minecraft:iron_ore"; + materials[16] = "minecraft:coal_ore"; + materials[17] = "minecraft:log"; + materials[18] = "minecraft:leaves"; + materials[19] = "minecraft:sponge"; + materials[20] = "minecraft:glass"; + materials[21] = "minecraft:lapis_ore"; + materials[22] = "minecraft:lapis_block"; + materials[23] = "minecraft:dispenser"; + materials[24] = "minecraft:sandstone"; + materials[25] = "minecraft:noteblock"; + materials[27] = "minecraft:golden_rail"; + materials[28] = "minecraft:detector_rail"; + materials[29] = "minecraft:sticky_piston"; + materials[30] = "minecraft:web"; + materials[31] = "minecraft:tallgrass"; + materials[32] = "minecraft:deadbush"; + materials[33] = "minecraft:piston"; + materials[35] = "minecraft:wool"; + materials[37] = "minecraft:yellow_flower"; + materials[38] = "minecraft:red_flower"; + materials[39] = "minecraft:brown_mushroom"; + materials[40] = "minecraft:red_mushroom"; + materials[41] = "minecraft:gold_block"; + materials[42] = "minecraft:iron_block"; + materials[43] = "minecraft:double_stone_slab"; + materials[44] = "minecraft:stone_slab"; + materials[45] = "minecraft:brick_block"; + materials[46] = "minecraft:tnt"; + materials[47] = "minecraft:bookshelf"; + materials[48] = "minecraft:mossy_cobblestone"; + materials[49] = "minecraft:obsidian"; + materials[50] = "minecraft:torch"; + materials[51] = "minecraft:fire"; + materials[52] = "minecraft:mob_spawner"; + materials[53] = "minecraft:oak_stairs"; + materials[54] = "minecraft:chest"; + materials[56] = "minecraft:diamond_ore"; + materials[57] = "minecraft:diamond_block"; + materials[58] = "minecraft:crafting_table"; + materials[60] = "minecraft:farmland"; + materials[61] = "minecraft:furnace"; + materials[62] = "minecraft:lit_furnace"; + materials[65] = "minecraft:ladder"; + materials[66] = "minecraft:rail"; + materials[67] = "minecraft:stone_stairs"; + materials[69] = "minecraft:lever"; + materials[70] = "minecraft:stone_pressure_plate"; + materials[72] = "minecraft:wooden_pressure_plate"; + materials[73] = "minecraft:redstone_ore"; + materials[76] = "minecraft:redstone_torch"; + materials[77] = "minecraft:stone_button"; + materials[78] = "minecraft:snow_layer"; + materials[79] = "minecraft:ice"; + materials[80] = "minecraft:snow"; + materials[81] = "minecraft:cactus"; + materials[82] = "minecraft:clay"; + materials[84] = "minecraft:jukebox"; + materials[85] = "minecraft:fence"; + materials[86] = "minecraft:pumpkin"; + materials[87] = "minecraft:netherrack"; + materials[88] = "minecraft:soul_sand"; + materials[89] = "minecraft:glowstone"; + materials[90] = "minecraft:portal"; + materials[91] = "minecraft:lit_pumpkin"; + materials[95] = "minecraft:stained_glass"; + materials[96] = "minecraft:trapdoor"; + materials[97] = "minecraft:monster_egg"; + materials[98] = "minecraft:stonebrick"; + materials[99] = "minecraft:brown_mushroom_block"; + materials[100] = "minecraft:red_mushroom_block"; + materials[101] = "minecraft:iron_bars"; + materials[102] = "minecraft:glass_pane"; + materials[103] = "minecraft:melon_block"; + materials[106] = "minecraft:vine"; + materials[107] = "minecraft:fence_gate"; + materials[108] = "minecraft:brick_stairs"; + materials[109] = "minecraft:stone_brick_stairs"; + materials[110] = "minecraft:mycelium"; + materials[111] = "minecraft:waterlily"; + materials[112] = "minecraft:nether_brick"; + materials[113] = "minecraft:nether_brick_fence"; + materials[114] = "minecraft:nether_brick_stairs"; + materials[116] = "minecraft:enchanting_table"; + materials[119] = "minecraft:end_portal"; + materials[120] = "minecraft:end_portal_frame"; + materials[121] = "minecraft:end_stone"; + materials[122] = "minecraft:dragon_egg"; + materials[123] = "minecraft:redstone_lamp"; + materials[125] = "minecraft:double_wooden_slab"; + materials[126] = "minecraft:wooden_slab"; + materials[127] = "minecraft:cocoa"; + materials[128] = "minecraft:sandstone_stairs"; + materials[129] = "minecraft:emerald_ore"; + materials[130] = "minecraft:ender_chest"; + materials[131] = "minecraft:tripwire_hook"; + materials[133] = "minecraft:emerald_block"; + materials[134] = "minecraft:spruce_stairs"; + materials[135] = "minecraft:birch_stairs"; + materials[136] = "minecraft:jungle_stairs"; + materials[137] = "minecraft:command_block"; + materials[138] = "minecraft:beacon"; + materials[139] = "minecraft:cobblestone_wall"; + materials[141] = "minecraft:carrots"; + materials[142] = "minecraft:potatoes"; + materials[143] = "minecraft:wooden_button"; + materials[145] = "minecraft:anvil"; + materials[146] = "minecraft:trapped_chest"; + materials[147] = "minecraft:light_weighted_pressure_plate"; + materials[148] = "minecraft:heavy_weighted_pressure_plate"; + materials[151] = "minecraft:daylight_detector"; + materials[152] = "minecraft:redstone_block"; + materials[153] = "minecraft:quartz_ore"; + materials[154] = "minecraft:hopper"; + materials[155] = "minecraft:quartz_block"; + materials[156] = "minecraft:quartz_stairs"; + materials[157] = "minecraft:activator_rail"; + materials[158] = "minecraft:dropper"; + materials[159] = "minecraft:stained_hardened_clay"; + materials[160] = "minecraft:stained_glass_pane"; + materials[161] = "minecraft:leaves2"; + materials[162] = "minecraft:log2"; + materials[163] = "minecraft:acacia_stairs"; + materials[164] = "minecraft:dark_oak_stairs"; + materials[170] = "minecraft:hay_block"; + materials[171] = "minecraft:carpet"; + materials[172] = "minecraft:hardened_clay"; + materials[173] = "minecraft:coal_block"; + materials[174] = "minecraft:packed_ice"; + materials[175] = "minecraft:double_plant"; + materials[256] = "minecraft:iron_shovel"; + materials[257] = "minecraft:iron_pickaxe"; + materials[258] = "minecraft:iron_axe"; + materials[259] = "minecraft:flint_and_steel"; + materials[260] = "minecraft:apple"; + materials[261] = "minecraft:bow"; + materials[262] = "minecraft:arrow"; + materials[263] = "minecraft:coal"; + materials[264] = "minecraft:diamond"; + materials[265] = "minecraft:iron_ingot"; + materials[266] = "minecraft:gold_ingot"; + materials[267] = "minecraft:iron_sword"; + materials[268] = "minecraft:wooden_sword"; + materials[269] = "minecraft:wooden_shovel"; + materials[270] = "minecraft:wooden_pickaxe"; + materials[271] = "minecraft:wooden_axe"; + materials[272] = "minecraft:stone_sword"; + materials[273] = "minecraft:stone_shovel"; + materials[274] = "minecraft:stone_pickaxe"; + materials[275] = "minecraft:stone_axe"; + materials[276] = "minecraft:diamond_sword"; + materials[277] = "minecraft:diamond_shovel"; + materials[278] = "minecraft:diamond_pickaxe"; + materials[279] = "minecraft:diamond_axe"; + materials[280] = "minecraft:stick"; + materials[281] = "minecraft:bowl"; + materials[282] = "minecraft:mushroom_stew"; + materials[283] = "minecraft:golden_sword"; + materials[284] = "minecraft:golden_shovel"; + materials[285] = "minecraft:golden_pickaxe"; + materials[286] = "minecraft:golden_axe"; + materials[287] = "minecraft:string"; + materials[288] = "minecraft:feather"; + materials[289] = "minecraft:gunpowder"; + materials[290] = "minecraft:wooden_hoe"; + materials[291] = "minecraft:stone_hoe"; + materials[292] = "minecraft:iron_hoe"; + materials[293] = "minecraft:diamond_hoe"; + materials[294] = "minecraft:golden_hoe"; + materials[295] = "minecraft:wheat_seeds"; + materials[296] = "minecraft:wheat"; + materials[297] = "minecraft:bread"; + materials[298] = "minecraft:leather_helmet"; + materials[299] = "minecraft:leather_chestplate"; + materials[300] = "minecraft:leather_leggings"; + materials[301] = "minecraft:leather_boots"; + materials[302] = "minecraft:chainmail_helmet"; + materials[303] = "minecraft:chainmail_chestplate"; + materials[304] = "minecraft:chainmail_leggings"; + materials[305] = "minecraft:chainmail_boots"; + materials[306] = "minecraft:iron_helmet"; + materials[307] = "minecraft:iron_chestplate"; + materials[308] = "minecraft:iron_leggings"; + materials[309] = "minecraft:iron_boots"; + materials[310] = "minecraft:diamond_helmet"; + materials[311] = "minecraft:diamond_chestplate"; + materials[312] = "minecraft:diamond_leggings"; + materials[313] = "minecraft:diamond_boots"; + materials[314] = "minecraft:golden_helmet"; + materials[315] = "minecraft:golden_chestplate"; + materials[316] = "minecraft:golden_leggings"; + materials[317] = "minecraft:golden_boots"; + materials[318] = "minecraft:flint"; + materials[319] = "minecraft:porkchop"; + materials[320] = "minecraft:cooked_porkchop"; + materials[321] = "minecraft:painting"; + materials[322] = "minecraft:golden_apple"; + materials[323] = "minecraft:sign"; + materials[324] = "minecraft:wooden_door"; + materials[325] = "minecraft:bucket"; + materials[326] = "minecraft:water_bucket"; + materials[327] = "minecraft:lava_bucket"; + materials[328] = "minecraft:minecart"; + materials[329] = "minecraft:saddle"; + materials[330] = "minecraft:iron_door"; + materials[331] = "minecraft:redstone"; + materials[332] = "minecraft:snowball"; + materials[333] = "minecraft:boat"; + materials[334] = "minecraft:leather"; + materials[335] = "minecraft:milk_bucket"; + materials[336] = "minecraft:brick"; + materials[337] = "minecraft:clay_ball"; + materials[338] = "minecraft:reeds"; + materials[339] = "minecraft:paper"; + materials[340] = "minecraft:book"; + materials[341] = "minecraft:slime_ball"; + materials[342] = "minecraft:chest_minecart"; + materials[343] = "minecraft:furnace_minecart"; + materials[344] = "minecraft:egg"; + materials[345] = "minecraft:compass"; + materials[346] = "minecraft:fishing_rod"; + materials[347] = "minecraft:clock"; + materials[348] = "minecraft:glowstone_dust"; + materials[349] = "minecraft:fish"; + materials[350] = "minecraft:cooked_fish"; // Paper - cooked_fished -> cooked_fish + materials[351] = "minecraft:dye"; + materials[352] = "minecraft:bone"; + materials[353] = "minecraft:sugar"; + materials[354] = "minecraft:cake"; + materials[355] = "minecraft:bed"; + materials[356] = "minecraft:repeater"; + materials[357] = "minecraft:cookie"; + materials[358] = "minecraft:filled_map"; + materials[359] = "minecraft:shears"; + materials[360] = "minecraft:melon"; + materials[361] = "minecraft:pumpkin_seeds"; + materials[362] = "minecraft:melon_seeds"; + materials[363] = "minecraft:beef"; + materials[364] = "minecraft:cooked_beef"; + materials[365] = "minecraft:chicken"; + materials[366] = "minecraft:cooked_chicken"; + materials[367] = "minecraft:rotten_flesh"; + materials[368] = "minecraft:ender_pearl"; + materials[369] = "minecraft:blaze_rod"; + materials[370] = "minecraft:ghast_tear"; + materials[371] = "minecraft:gold_nugget"; + materials[372] = "minecraft:nether_wart"; + materials[373] = "minecraft:potion"; + materials[374] = "minecraft:glass_bottle"; + materials[375] = "minecraft:spider_eye"; + materials[376] = "minecraft:fermented_spider_eye"; + materials[377] = "minecraft:blaze_powder"; + materials[378] = "minecraft:magma_cream"; + materials[379] = "minecraft:brewing_stand"; + materials[380] = "minecraft:cauldron"; + materials[381] = "minecraft:ender_eye"; + materials[382] = "minecraft:speckled_melon"; + materials[383] = "minecraft:spawn_egg"; + materials[384] = "minecraft:experience_bottle"; + materials[385] = "minecraft:fire_charge"; + materials[386] = "minecraft:writable_book"; + materials[387] = "minecraft:written_book"; + materials[388] = "minecraft:emerald"; + materials[389] = "minecraft:item_frame"; + materials[390] = "minecraft:flower_pot"; + materials[391] = "minecraft:carrot"; + materials[392] = "minecraft:potato"; + materials[393] = "minecraft:baked_potato"; + materials[394] = "minecraft:poisonous_potato"; + materials[395] = "minecraft:map"; + materials[396] = "minecraft:golden_carrot"; + materials[397] = "minecraft:skull"; + materials[398] = "minecraft:carrot_on_a_stick"; + materials[399] = "minecraft:nether_star"; + materials[400] = "minecraft:pumpkin_pie"; + materials[401] = "minecraft:fireworks"; + materials[402] = "minecraft:firework_charge"; + materials[403] = "minecraft:enchanted_book"; + materials[404] = "minecraft:comparator"; + materials[405] = "minecraft:netherbrick"; + materials[406] = "minecraft:quartz"; + materials[407] = "minecraft:tnt_minecart"; + materials[408] = "minecraft:hopper_minecart"; + materials[417] = "minecraft:iron_horse_armor"; + materials[418] = "minecraft:golden_horse_armor"; + materials[419] = "minecraft:diamond_horse_armor"; + materials[420] = "minecraft:lead"; + materials[421] = "minecraft:name_tag"; + materials[422] = "minecraft:command_block_minecart"; + materials[2256] = "minecraft:record_13"; + materials[2257] = "minecraft:record_cat"; + materials[2258] = "minecraft:record_blocks"; + materials[2259] = "minecraft:record_chirp"; + materials[2260] = "minecraft:record_far"; + materials[2261] = "minecraft:record_mall"; + materials[2262] = "minecraft:record_mellohi"; + materials[2263] = "minecraft:record_stal"; + materials[2264] = "minecraft:record_strad"; + materials[2265] = "minecraft:record_ward"; + materials[2266] = "minecraft:record_11"; + materials[2267] = "minecraft:record_wait"; + // Paper start + materials[409] = "minecraft:prismarine_shard"; + materials[410] = "minecraft:prismarine_crystals"; + materials[411] = "minecraft:rabbit"; + materials[412] = "minecraft:cooked_rabbit"; + materials[413] = "minecraft:rabbit_stew"; + materials[414] = "minecraft:rabbit_foot"; + materials[415] = "minecraft:rabbit_hide"; + materials[416] = "minecraft:armor_stand"; + materials[423] = "minecraft:mutton"; + materials[424] = "minecraft:cooked_mutton"; + materials[425] = "minecraft:banner"; + materials[426] = "minecraft:end_crystal"; + materials[427] = "minecraft:spruce_door"; + materials[428] = "minecraft:birch_door"; + materials[429] = "minecraft:jungle_door"; + materials[430] = "minecraft:acacia_door"; + materials[431] = "minecraft:dark_oak_door"; + materials[432] = "minecraft:chorus_fruit"; + materials[433] = "minecraft:chorus_fruit_popped"; + materials[434] = "minecraft:beetroot"; + materials[435] = "minecraft:beetroot_seeds"; + materials[436] = "minecraft:beetroot_soup"; + materials[437] = "minecraft:dragon_breath"; + materials[438] = "minecraft:splash_potion"; + materials[439] = "minecraft:spectral_arrow"; + materials[440] = "minecraft:tipped_arrow"; + materials[441] = "minecraft:lingering_potion"; + materials[442] = "minecraft:shield"; + materials[443] = "minecraft:elytra"; + materials[444] = "minecraft:spruce_boat"; + materials[445] = "minecraft:birch_boat"; + materials[446] = "minecraft:jungle_boat"; + materials[447] = "minecraft:acacia_boat"; + materials[448] = "minecraft:dark_oak_boat"; + materials[449] = "minecraft:totem_of_undying"; + materials[450] = "minecraft:shulker_shell"; + materials[452] = "minecraft:iron_nugget"; + materials[453] = "minecraft:knowledge_book"; + // Paper end + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() { + } + + public int getDataVersion() { + return 147; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { + cmp.remove("Silent"); + } + + return cmp; + } + + } + + private static class DataConverterBanner implements DataConverter { + + DataConverterBanner() { + } + + public int getDataVersion() { + return 804; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); + + if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { + return cmp; + } + } + } + + nbttagcompound2.remove("Base"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + } + } + } + + return cmp; + } + + } + + private static class DataConverterPotionId implements DataConverter { + + private static final String[] potions = new String[128]; + + DataConverterPotionId() { + } + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound1.contains("Potion", 8)) { + String s = DataConverterPotionId.potions[short0 & 127]; + + nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); + cmp.put("tag", nbttagcompound1); + if ((short0 & 16384) == 16384) { + cmp.putString("id", "minecraft:splash_potion"); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + DataConverterPotionId.potions[0] = "minecraft:water"; + DataConverterPotionId.potions[1] = "minecraft:regeneration"; + DataConverterPotionId.potions[2] = "minecraft:swiftness"; + DataConverterPotionId.potions[3] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[4] = "minecraft:poison"; + DataConverterPotionId.potions[5] = "minecraft:healing"; + DataConverterPotionId.potions[6] = "minecraft:night_vision"; + DataConverterPotionId.potions[7] = null; + DataConverterPotionId.potions[8] = "minecraft:weakness"; + DataConverterPotionId.potions[9] = "minecraft:strength"; + DataConverterPotionId.potions[10] = "minecraft:slowness"; + DataConverterPotionId.potions[11] = "minecraft:leaping"; + DataConverterPotionId.potions[12] = "minecraft:harming"; + DataConverterPotionId.potions[13] = "minecraft:water_breathing"; + DataConverterPotionId.potions[14] = "minecraft:invisibility"; + DataConverterPotionId.potions[15] = null; + DataConverterPotionId.potions[16] = "minecraft:awkward"; + DataConverterPotionId.potions[17] = "minecraft:regeneration"; + DataConverterPotionId.potions[18] = "minecraft:swiftness"; + DataConverterPotionId.potions[19] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[20] = "minecraft:poison"; + DataConverterPotionId.potions[21] = "minecraft:healing"; + DataConverterPotionId.potions[22] = "minecraft:night_vision"; + DataConverterPotionId.potions[23] = null; + DataConverterPotionId.potions[24] = "minecraft:weakness"; + DataConverterPotionId.potions[25] = "minecraft:strength"; + DataConverterPotionId.potions[26] = "minecraft:slowness"; + DataConverterPotionId.potions[27] = "minecraft:leaping"; + DataConverterPotionId.potions[28] = "minecraft:harming"; + DataConverterPotionId.potions[29] = "minecraft:water_breathing"; + DataConverterPotionId.potions[30] = "minecraft:invisibility"; + DataConverterPotionId.potions[31] = null; + DataConverterPotionId.potions[32] = "minecraft:thick"; + DataConverterPotionId.potions[33] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[34] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[35] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[36] = "minecraft:strong_poison"; + DataConverterPotionId.potions[37] = "minecraft:strong_healing"; + DataConverterPotionId.potions[38] = "minecraft:night_vision"; + DataConverterPotionId.potions[39] = null; + DataConverterPotionId.potions[40] = "minecraft:weakness"; + DataConverterPotionId.potions[41] = "minecraft:strong_strength"; + DataConverterPotionId.potions[42] = "minecraft:slowness"; + DataConverterPotionId.potions[43] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[44] = "minecraft:strong_harming"; + DataConverterPotionId.potions[45] = "minecraft:water_breathing"; + DataConverterPotionId.potions[46] = "minecraft:invisibility"; + DataConverterPotionId.potions[47] = null; + DataConverterPotionId.potions[48] = null; + DataConverterPotionId.potions[49] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[50] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[51] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[52] = "minecraft:strong_poison"; + DataConverterPotionId.potions[53] = "minecraft:strong_healing"; + DataConverterPotionId.potions[54] = "minecraft:night_vision"; + DataConverterPotionId.potions[55] = null; + DataConverterPotionId.potions[56] = "minecraft:weakness"; + DataConverterPotionId.potions[57] = "minecraft:strong_strength"; + DataConverterPotionId.potions[58] = "minecraft:slowness"; + DataConverterPotionId.potions[59] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[60] = "minecraft:strong_harming"; + DataConverterPotionId.potions[61] = "minecraft:water_breathing"; + DataConverterPotionId.potions[62] = "minecraft:invisibility"; + DataConverterPotionId.potions[63] = null; + DataConverterPotionId.potions[64] = "minecraft:mundane"; + DataConverterPotionId.potions[65] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[66] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[67] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[68] = "minecraft:long_poison"; + DataConverterPotionId.potions[69] = "minecraft:healing"; + DataConverterPotionId.potions[70] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[71] = null; + DataConverterPotionId.potions[72] = "minecraft:long_weakness"; + DataConverterPotionId.potions[73] = "minecraft:long_strength"; + DataConverterPotionId.potions[74] = "minecraft:long_slowness"; + DataConverterPotionId.potions[75] = "minecraft:long_leaping"; + DataConverterPotionId.potions[76] = "minecraft:harming"; + DataConverterPotionId.potions[77] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[78] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[79] = null; + DataConverterPotionId.potions[80] = "minecraft:awkward"; + DataConverterPotionId.potions[81] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[82] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[83] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[84] = "minecraft:long_poison"; + DataConverterPotionId.potions[85] = "minecraft:healing"; + DataConverterPotionId.potions[86] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[87] = null; + DataConverterPotionId.potions[88] = "minecraft:long_weakness"; + DataConverterPotionId.potions[89] = "minecraft:long_strength"; + DataConverterPotionId.potions[90] = "minecraft:long_slowness"; + DataConverterPotionId.potions[91] = "minecraft:long_leaping"; + DataConverterPotionId.potions[92] = "minecraft:harming"; + DataConverterPotionId.potions[93] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[94] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[95] = null; + DataConverterPotionId.potions[96] = "minecraft:thick"; + DataConverterPotionId.potions[97] = "minecraft:regeneration"; + DataConverterPotionId.potions[98] = "minecraft:swiftness"; + DataConverterPotionId.potions[99] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[100] = "minecraft:poison"; + DataConverterPotionId.potions[101] = "minecraft:strong_healing"; + DataConverterPotionId.potions[102] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[103] = null; + DataConverterPotionId.potions[104] = "minecraft:long_weakness"; + DataConverterPotionId.potions[105] = "minecraft:strength"; + DataConverterPotionId.potions[106] = "minecraft:long_slowness"; + DataConverterPotionId.potions[107] = "minecraft:leaping"; + DataConverterPotionId.potions[108] = "minecraft:strong_harming"; + DataConverterPotionId.potions[109] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[110] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[111] = null; + DataConverterPotionId.potions[112] = null; + DataConverterPotionId.potions[113] = "minecraft:regeneration"; + DataConverterPotionId.potions[114] = "minecraft:swiftness"; + DataConverterPotionId.potions[115] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[116] = "minecraft:poison"; + DataConverterPotionId.potions[117] = "minecraft:strong_healing"; + DataConverterPotionId.potions[118] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[119] = null; + DataConverterPotionId.potions[120] = "minecraft:long_weakness"; + DataConverterPotionId.potions[121] = "minecraft:strength"; + DataConverterPotionId.potions[122] = "minecraft:long_slowness"; + DataConverterPotionId.potions[123] = "minecraft:leaping"; + DataConverterPotionId.potions[124] = "minecraft:strong_harming"; + DataConverterPotionId.potions[125] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[127] = null; + } + } + + private static class DataConverterSpawnEgg implements DataConverter { + + private static final String[] eggs = new String[256]; + + DataConverterSpawnEgg() { + } + + public int getDataVersion() { + return 105; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound2.contains("id", 8)) { + String s = DataConverterSpawnEgg.eggs[short0 & 255]; + + if (s != null) { + nbttagcompound2.putString("id", s); + nbttagcompound1.put("EntityTag", nbttagcompound2); + cmp.put("tag", nbttagcompound1); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + + DataConverterSpawnEgg.eggs[1] = "Item"; + DataConverterSpawnEgg.eggs[2] = "XPOrb"; + DataConverterSpawnEgg.eggs[7] = "ThrownEgg"; + DataConverterSpawnEgg.eggs[8] = "LeashKnot"; + DataConverterSpawnEgg.eggs[9] = "Painting"; + DataConverterSpawnEgg.eggs[10] = "Arrow"; + DataConverterSpawnEgg.eggs[11] = "Snowball"; + DataConverterSpawnEgg.eggs[12] = "Fireball"; + DataConverterSpawnEgg.eggs[13] = "SmallFireball"; + DataConverterSpawnEgg.eggs[14] = "ThrownEnderpearl"; + DataConverterSpawnEgg.eggs[15] = "EyeOfEnderSignal"; + DataConverterSpawnEgg.eggs[16] = "ThrownPotion"; + DataConverterSpawnEgg.eggs[17] = "ThrownExpBottle"; + DataConverterSpawnEgg.eggs[18] = "ItemFrame"; + DataConverterSpawnEgg.eggs[19] = "WitherSkull"; + DataConverterSpawnEgg.eggs[20] = "PrimedTnt"; + DataConverterSpawnEgg.eggs[21] = "FallingSand"; + DataConverterSpawnEgg.eggs[22] = "FireworksRocketEntity"; + DataConverterSpawnEgg.eggs[23] = "TippedArrow"; + DataConverterSpawnEgg.eggs[24] = "SpectralArrow"; + DataConverterSpawnEgg.eggs[25] = "ShulkerBullet"; + DataConverterSpawnEgg.eggs[26] = "DragonFireball"; + DataConverterSpawnEgg.eggs[30] = "ArmorStand"; + DataConverterSpawnEgg.eggs[41] = "Boat"; + DataConverterSpawnEgg.eggs[42] = "MinecartRideable"; + DataConverterSpawnEgg.eggs[43] = "MinecartChest"; + DataConverterSpawnEgg.eggs[44] = "MinecartFurnace"; + DataConverterSpawnEgg.eggs[45] = "MinecartTNT"; + DataConverterSpawnEgg.eggs[46] = "MinecartHopper"; + DataConverterSpawnEgg.eggs[47] = "MinecartSpawner"; + DataConverterSpawnEgg.eggs[40] = "MinecartCommandBlock"; + DataConverterSpawnEgg.eggs[48] = "Mob"; + DataConverterSpawnEgg.eggs[49] = "Monster"; + DataConverterSpawnEgg.eggs[50] = "Creeper"; + DataConverterSpawnEgg.eggs[51] = "Skeleton"; + DataConverterSpawnEgg.eggs[52] = "Spider"; + DataConverterSpawnEgg.eggs[53] = "Giant"; + DataConverterSpawnEgg.eggs[54] = "Zombie"; + DataConverterSpawnEgg.eggs[55] = "Slime"; + DataConverterSpawnEgg.eggs[56] = "Ghast"; + DataConverterSpawnEgg.eggs[57] = "PigZombie"; + DataConverterSpawnEgg.eggs[58] = "Enderman"; + DataConverterSpawnEgg.eggs[59] = "CaveSpider"; + DataConverterSpawnEgg.eggs[60] = "Silverfish"; + DataConverterSpawnEgg.eggs[61] = "Blaze"; + DataConverterSpawnEgg.eggs[62] = "LavaSlime"; + DataConverterSpawnEgg.eggs[63] = "EnderDragon"; + DataConverterSpawnEgg.eggs[64] = "WitherBoss"; + DataConverterSpawnEgg.eggs[65] = "Bat"; + DataConverterSpawnEgg.eggs[66] = "Witch"; + DataConverterSpawnEgg.eggs[67] = "Endermite"; + DataConverterSpawnEgg.eggs[68] = "Guardian"; + DataConverterSpawnEgg.eggs[69] = "Shulker"; + DataConverterSpawnEgg.eggs[90] = "Pig"; + DataConverterSpawnEgg.eggs[91] = "Sheep"; + DataConverterSpawnEgg.eggs[92] = "Cow"; + DataConverterSpawnEgg.eggs[93] = "Chicken"; + DataConverterSpawnEgg.eggs[94] = "Squid"; + DataConverterSpawnEgg.eggs[95] = "Wolf"; + DataConverterSpawnEgg.eggs[96] = "MushroomCow"; + DataConverterSpawnEgg.eggs[97] = "SnowMan"; + DataConverterSpawnEgg.eggs[98] = "Ozelot"; + DataConverterSpawnEgg.eggs[99] = "VillagerGolem"; + DataConverterSpawnEgg.eggs[100] = "EntityHorse"; + DataConverterSpawnEgg.eggs[101] = "Rabbit"; + DataConverterSpawnEgg.eggs[120] = "Villager"; + DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; + } + } + + private static class DataConverterMinecart implements DataConverter { + + private static final List a = Lists.newArrayList( + "MinecartRideable", + "MinecartChest", + "MinecartFurnace", + "MinecartTNT", + "MinecartSpawner", + "MinecartHopper", + "MinecartCommandBlock" + ); + + DataConverterMinecart() { + } + + public int getDataVersion() { + return 106; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Minecart".equals(cmp.getString("id"))) { + String s = "MinecartRideable"; + int i = cmp.getInt("Type"); + + if (i > 0 && i < DataConverterMinecart.a.size()) { + s = DataConverterMinecart.a.get(i); + } + + cmp.putString("id", s); + cmp.remove("Type"); + } + + return cmp; + } + + } + + private static class DataConverterMobSpawner implements DataConverter { + + DataConverterMobSpawner() { + } + + public int getDataVersion() { + return 107; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + + nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); + nbttagcompound2.put("Entity", nbttagcompound3); + nbttagcompound2.remove("Type"); + nbttagcompound2.remove("Properties"); + } + } + } + + return cmp; + } + } + + } + + private static class DataConverterUUID implements DataConverter { + + DataConverterUUID() { + } + + public int getDataVersion() { + return 108; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("UUID", 8)) { + cmp.putUUID("UUID", UUID.fromString(cmp.getString("UUID"))); + } + + return cmp; + } + + } + + private static class DataConverterHealth implements DataConverter { + + private static final Set a = Sets.newHashSet( + "ArmorStand", + "Bat", + "Blaze", + "CaveSpider", + "Chicken", + "Cow", + "Creeper", + "EnderDragon", + "Enderman", + "Endermite", + "EntityHorse", + "Ghast", + "Giant", + "Guardian", + "LavaSlime", + "MushroomCow", + "Ozelot", + "Pig", + "PigZombie", + "Rabbit", + "Sheep", + "Shulker", + "Silverfish", + "Skeleton", + "Slime", + "SnowMan", + "Spider", + "Squid", + "Villager", + "VillagerGolem", + "Witch", + "WitherBoss", + "Wolf", + "Zombie" + ); + + DataConverterHealth() { + } + + public int getDataVersion() { + return 109; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (DataConverterHealth.a.contains(cmp.getString("id"))) { + float f; + + if (cmp.contains("HealF", 99)) { + f = cmp.getFloat("HealF"); + cmp.remove("HealF"); + } else { + if (!cmp.contains("Health", 99)) { + return cmp; + } + + f = cmp.getFloat("Health"); + } + + cmp.putFloat("Health", f); + } + + return cmp; + } + + } + + private static class DataConverterSaddle implements DataConverter { + + DataConverterSaddle() { + } + + public int getDataVersion() { + return 110; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound1.putString("id", "minecraft:saddle"); + nbttagcompound1.putByte("Count", (byte) 1); + nbttagcompound1.putShort("Damage", (short) 0); + cmp.put("SaddleItem", nbttagcompound1); + cmp.remove("Saddle"); + } + + return cmp; + } + + } + + private static class DataConverterHanging implements DataConverter { + + DataConverterHanging() { + } + + public int getDataVersion() { + return 111; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + boolean flag = "Painting".equals(s); + boolean flag1 = "ItemFrame".equals(s); + + if ((flag || flag1) && !cmp.contains("Facing", 99)) { + Direction enumdirection; + + if (cmp.contains("Direction", 99)) { + enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); + } + + return cmp; + } + + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() { + } + + public int getDataVersion() { + return 113; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + net.minecraft.nbt.ListTag nbttaglist; + + if (cmp.contains("HandDropChances", 9)) { + nbttaglist = cmp.getList("HandDropChances", 5); + if (nbttaglist.size() == 2 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F) { + cmp.remove("HandDropChances"); + } + } + + if (cmp.contains("ArmorDropChances", 9)) { + nbttaglist = cmp.getList("ArmorDropChances", 5); + if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat( + 2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) { + cmp.remove("ArmorDropChances"); + } + } + + return cmp; + } + + } + + private static class DataConverterRiding implements DataConverter { + + DataConverterRiding() { + } + + public int getDataVersion() { + return 135; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + while (cmp.contains("Riding", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(net.minecraft.nbt.CompoundTag nbttagcompound, net.minecraft.nbt.CompoundTag nbttagcompound1) { + net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.ListTag(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected net.minecraft.nbt.CompoundTag b(net.minecraft.nbt.CompoundTag nbttagcompound) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() { + } + + public int getDataVersion() { + return 165; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Component object = null; + + if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = new TextComponent(s); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = new TextComponent(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponent(s); + } + } + } else { + object = new TextComponent(""); + } + + nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final ResourceLocation a = new ResourceLocation("cooked_fished"); + + DataConverterCookedFish() { + } + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "minecraft:cooked_fish"); + } + + return cmp; + } + + } + + private static class DataConverterZombie implements DataConverter { + + private static final Random a = new Random(); + + DataConverterZombie() { + } + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { + if (!cmp.contains("ZombieType", 99)) { + int i = -1; + + if (cmp.contains("VillagerProfession", 99)) { + try { + i = this.convert(cmp.getInt("VillagerProfession")); + } catch (RuntimeException runtimeexception) { + ; + } + } + + if (i == -1) { + i = this.convert(DataConverterZombie.a.nextInt(6)); + } + + cmp.putInt("ZombieType", i); + } + + cmp.remove("IsVillager"); + } + + return cmp; + } + + private int convert(int i) { + return i >= 0 && i < 6 ? i : -1; + } + + } + + private static class DataConverterVBO implements DataConverter { + + DataConverterVBO() { + } + + public int getDataVersion() { + return 505; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() { + } + + public int getDataVersion() { + return 700; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Guardian".equals(cmp.getString("id"))) { + if (cmp.getBoolean("Elder")) { + cmp.putString("id", "ElderGuardian"); + } + + cmp.remove("Elder"); + } + + return cmp; + } + + } + + private static class DataConverterSkeleton implements DataConverter { + + DataConverterSkeleton() { + } + + public int getDataVersion() { + return 701; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("Skeleton".equals(s)) { + int i = cmp.getInt("SkeletonType"); + + if (i == 1) { + cmp.putString("id", "WitherSkeleton"); + } else if (i == 2) { + cmp.putString("id", "Stray"); + } + + cmp.remove("SkeletonType"); + } + + return cmp; + } + + } + + private static class DataConverterZombieType implements DataConverter { + + DataConverterZombieType() { + } + + public int getDataVersion() { + return 702; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 0: + default: + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + cmp.putString("id", "ZombieVillager"); + cmp.putInt("Profession", i - 1); + break; + + case 6: + cmp.putString("id", "Husk"); + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() { + } + + public int getDataVersion() { + return 703; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 0: + default: + cmp.putString("id", "Horse"); + break; + + case 1: + cmp.putString("id", "Donkey"); + break; + + case 2: + cmp.putString("id", "Mule"); + break; + + case 3: + cmp.putString("id", "ZombieHorse"); + break; + + case 4: + cmp.putString("id", "SkeletonHorse"); + } + + cmp.remove("Type"); + } + + return cmp; + } + + } + + private static class DataConverterTileEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterTileEntity() { + } + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterTileEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterTileEntity.a.put("Airportal", "minecraft:end_portal"); + DataConverterTileEntity.a.put("Banner", "minecraft:banner"); + DataConverterTileEntity.a.put("Beacon", "minecraft:beacon"); + DataConverterTileEntity.a.put("Cauldron", "minecraft:brewing_stand"); + DataConverterTileEntity.a.put("Chest", "minecraft:chest"); + DataConverterTileEntity.a.put("Comparator", "minecraft:comparator"); + DataConverterTileEntity.a.put("Control", "minecraft:command_block"); + DataConverterTileEntity.a.put("DLDetector", "minecraft:daylight_detector"); + DataConverterTileEntity.a.put("Dropper", "minecraft:dropper"); + DataConverterTileEntity.a.put("EnchantTable", "minecraft:enchanting_table"); + DataConverterTileEntity.a.put("EndGateway", "minecraft:end_gateway"); + DataConverterTileEntity.a.put("EnderChest", "minecraft:ender_chest"); + DataConverterTileEntity.a.put("FlowerPot", "minecraft:flower_pot"); + DataConverterTileEntity.a.put("Furnace", "minecraft:furnace"); + DataConverterTileEntity.a.put("Hopper", "minecraft:hopper"); + DataConverterTileEntity.a.put("MobSpawner", "minecraft:mob_spawner"); + DataConverterTileEntity.a.put("Music", "minecraft:noteblock"); + DataConverterTileEntity.a.put("Piston", "minecraft:piston"); + DataConverterTileEntity.a.put("RecordPlayer", "minecraft:jukebox"); + DataConverterTileEntity.a.put("Sign", "minecraft:sign"); + DataConverterTileEntity.a.put("Skull", "minecraft:skull"); + DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); + DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); + } + } + + private static class DataConverterEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterEntity() { + } + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); + DataConverterEntity.a.put("ArmorStand", "minecraft:armor_stand"); + DataConverterEntity.a.put("Arrow", "minecraft:arrow"); + DataConverterEntity.a.put("Bat", "minecraft:bat"); + DataConverterEntity.a.put("Blaze", "minecraft:blaze"); + DataConverterEntity.a.put("Boat", "minecraft:boat"); + DataConverterEntity.a.put("CaveSpider", "minecraft:cave_spider"); + DataConverterEntity.a.put("Chicken", "minecraft:chicken"); + DataConverterEntity.a.put("Cow", "minecraft:cow"); + DataConverterEntity.a.put("Creeper", "minecraft:creeper"); + DataConverterEntity.a.put("Donkey", "minecraft:donkey"); + DataConverterEntity.a.put("DragonFireball", "minecraft:dragon_fireball"); + DataConverterEntity.a.put("ElderGuardian", "minecraft:elder_guardian"); + DataConverterEntity.a.put("EnderCrystal", "minecraft:ender_crystal"); + DataConverterEntity.a.put("EnderDragon", "minecraft:ender_dragon"); + DataConverterEntity.a.put("Enderman", "minecraft:enderman"); + DataConverterEntity.a.put("Endermite", "minecraft:endermite"); + DataConverterEntity.a.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); + DataConverterEntity.a.put("FallingSand", "minecraft:falling_block"); + DataConverterEntity.a.put("Fireball", "minecraft:fireball"); + DataConverterEntity.a.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); + DataConverterEntity.a.put("Ghast", "minecraft:ghast"); + DataConverterEntity.a.put("Giant", "minecraft:giant"); + DataConverterEntity.a.put("Guardian", "minecraft:guardian"); + DataConverterEntity.a.put("Horse", "minecraft:horse"); + DataConverterEntity.a.put("Husk", "minecraft:husk"); + DataConverterEntity.a.put("Item", "minecraft:item"); + DataConverterEntity.a.put("ItemFrame", "minecraft:item_frame"); + DataConverterEntity.a.put("LavaSlime", "minecraft:magma_cube"); + DataConverterEntity.a.put("LeashKnot", "minecraft:leash_knot"); + DataConverterEntity.a.put("MinecartChest", "minecraft:chest_minecart"); + DataConverterEntity.a.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); + DataConverterEntity.a.put("MinecartFurnace", "minecraft:furnace_minecart"); + DataConverterEntity.a.put("MinecartHopper", "minecraft:hopper_minecart"); + DataConverterEntity.a.put("MinecartRideable", "minecraft:minecart"); + DataConverterEntity.a.put("MinecartSpawner", "minecraft:spawner_minecart"); + DataConverterEntity.a.put("MinecartTNT", "minecraft:tnt_minecart"); + DataConverterEntity.a.put("Mule", "minecraft:mule"); + DataConverterEntity.a.put("MushroomCow", "minecraft:mooshroom"); + DataConverterEntity.a.put("Ozelot", "minecraft:ocelot"); + DataConverterEntity.a.put("Painting", "minecraft:painting"); + DataConverterEntity.a.put("Pig", "minecraft:pig"); + DataConverterEntity.a.put("PigZombie", "minecraft:zombie_pigman"); + DataConverterEntity.a.put("PolarBear", "minecraft:polar_bear"); + DataConverterEntity.a.put("PrimedTnt", "minecraft:tnt"); + DataConverterEntity.a.put("Rabbit", "minecraft:rabbit"); + DataConverterEntity.a.put("Sheep", "minecraft:sheep"); + DataConverterEntity.a.put("Shulker", "minecraft:shulker"); + DataConverterEntity.a.put("ShulkerBullet", "minecraft:shulker_bullet"); + DataConverterEntity.a.put("Silverfish", "minecraft:silverfish"); + DataConverterEntity.a.put("Skeleton", "minecraft:skeleton"); + DataConverterEntity.a.put("SkeletonHorse", "minecraft:skeleton_horse"); + DataConverterEntity.a.put("Slime", "minecraft:slime"); + DataConverterEntity.a.put("SmallFireball", "minecraft:small_fireball"); + DataConverterEntity.a.put("SnowMan", "minecraft:snowman"); + DataConverterEntity.a.put("Snowball", "minecraft:snowball"); + DataConverterEntity.a.put("SpectralArrow", "minecraft:spectral_arrow"); + DataConverterEntity.a.put("Spider", "minecraft:spider"); + DataConverterEntity.a.put("Squid", "minecraft:squid"); + DataConverterEntity.a.put("Stray", "minecraft:stray"); + DataConverterEntity.a.put("ThrownEgg", "minecraft:egg"); + DataConverterEntity.a.put("ThrownEnderpearl", "minecraft:ender_pearl"); + DataConverterEntity.a.put("ThrownExpBottle", "minecraft:xp_bottle"); + DataConverterEntity.a.put("ThrownPotion", "minecraft:potion"); + DataConverterEntity.a.put("Villager", "minecraft:villager"); + DataConverterEntity.a.put("VillagerGolem", "minecraft:villager_golem"); + DataConverterEntity.a.put("Witch", "minecraft:witch"); + DataConverterEntity.a.put("WitherBoss", "minecraft:wither"); + DataConverterEntity.a.put("WitherSkeleton", "minecraft:wither_skeleton"); + DataConverterEntity.a.put("WitherSkull", "minecraft:wither_skull"); + DataConverterEntity.a.put("Wolf", "minecraft:wolf"); + DataConverterEntity.a.put("XPOrb", "minecraft:xp_orb"); + DataConverterEntity.a.put("Zombie", "minecraft:zombie"); + DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); + DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); + } + } + + private static class DataConverterPotionWater implements DataConverter { + + DataConverterPotionWater() { + } + + public int getDataVersion() { + return 806; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals( + s)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (!nbttagcompound1.contains("Potion", 8)) { + nbttagcompound1.putString("Potion", "minecraft:water"); + } + + if (!cmp.contains("tag", 10)) { + cmp.put("tag", nbttagcompound1); + } + } + + return cmp; + } + + } + + private static class DataConverterShulker implements DataConverter { + + DataConverterShulker() { + } + + public int getDataVersion() { + return 808; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { + cmp.putByte("Color", (byte) 10); + } + + return cmp; + } + + } + + private static class DataConverterShulkerBoxItem implements DataConverter { + + public static final String[] a = new String[]{"minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box"}; + + DataConverterShulkerBoxItem() { + } + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.getList("Items", 10).isEmpty()) { + nbttagcompound2.remove("Items"); + } + + int i = nbttagcompound2.getInt("Color"); + + nbttagcompound2.remove("Color"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + + cmp.putString("id", DataConverterShulkerBoxItem.a[i % 16]); + } + } + + return cmp; + } + + } + + private static class DataConverterShulkerBoxBlock implements DataConverter { + + DataConverterShulkerBoxBlock() { + } + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id"))) { + cmp.remove("Color"); + } + + return cmp; + } + + } + + private static class DataConverterLang implements DataConverter { + + DataConverterLang() { + } + + public int getDataVersion() { + return 816; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.contains("lang", 8)) { + cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); + } + + return cmp; + } + + } + + private static class DataConverterTotem implements DataConverter { + + DataConverterTotem() { + } + + public int getDataVersion() { + return 820; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:totem".equals(cmp.getString("id"))) { + cmp.putString("id", "minecraft:totem_of_undying"); + } + + return cmp; + } + + } + + private static class DataConverterBedBlock implements DataConverter { + + private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class); + + DataConverterBedBlock() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + try { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist1.getCompound(k); + byte b0 = nbttagcompound2.getByte("Y"); + byte[] abyte = nbttagcompound2.getByteArray("Blocks"); + + for (int l = 0; l < abyte.length; ++l) { + if (416 == (abyte[l] & 255) << 4) { + int i1 = l & 15; + int j1 = l >> 8 & 15; + int k1 = l >> 4 & 15; + net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() { + } + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws + JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return new TextComponent(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + MutableComponent ichatbasecomponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + MutableComponent ichatbasecomponent1 = this.a( + jsonelement1, + jsonelement1.getClass(), + jsondeserializationcontext + ); + + if (ichatbasecomponent == null) { + ichatbasecomponent = ichatbasecomponent1; + } else { + ichatbasecomponent.append(ichatbasecomponent1); + } + } + + return ichatbasecomponent; + } else { + throw new JsonParseException("Don't know how to turn " + jsonelement + " into a Component"); + } + } + + public Object deserialize( + JsonElement jsonelement, + Type type, + JsonDeserializationContext jsondeserializationcontext + ) throws JsonParseException { + return this.a(jsonelement, type, jsondeserializationcontext); + } + }).create(); + + DataConverterSignText() { + } + + public int getDataVersion() { + return 101; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Sign".equals(cmp.getString("id"))) { + this.convert(cmp, "Text1"); + this.convert(cmp, "Text2"); + this.convert(cmp, "Text3"); + this.convert(cmp, "Text4"); + } + + return cmp; + } + + private void convert(net.minecraft.nbt.CompoundTag nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Component object = null; + + if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = new TextComponent(s1); + } else { + try { + object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = new TextComponent(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonLenient(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponent(s1); + } + } + } else { + object = new TextComponent(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJson(object)); + } + + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); + + if (nbttagcompound1.contains("Entity", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + return cmp; + } + + } + + private static class DataInspectorLevelPlayer implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Player", 10)) { + convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); + } + + return cmp; + } + + } + + private static class DataInspectorStructure implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.ListTag nbttaglist; + int j; + net.minecraft.nbt.CompoundTag nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + if (cmp.contains("blocks", 9)) { + nbttaglist = cmp.getList("blocks", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + return cmp; + } + + } + + private static class DataInspectorChunks implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + net.minecraft.nbt.ListTag nbttaglist; + int j; + + if (nbttagcompound1.contains("Entities", 9)) { + nbttaglist = nbttagcompound1.getList("Entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set( + j, + convert( + LegacyType.ENTITY, + (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), + sourceVer, + targetVer + ) + ); + } + } + + if (nbttagcompound1.contains("TileEntities", 9)) { + nbttaglist = nbttagcompound1.getList("TileEntities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set( + j, + convert( + LegacyType.BLOCK_ENTITY, + (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), + sourceVer, + targetVer + ) + ); + } + } + } + + return cmp; + } + + } + + private static class DataInspectorEntityPassengers implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Passengers", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + return cmp; + } + + } + + private static class DataInspectorPlayer implements DataInspector { + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + convertItems(cmp, "Inventory", sourceVer, targetVer); + convertItems(cmp, "EnderItems", sourceVer, targetVer); + if (cmp.contains("ShoulderEntityLeft", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityLeft", sourceVer, targetVer); + } + + if (cmp.contains("ShoulderEntityRight", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityRight", sourceVer, targetVer); + } + + return cmp; + } + + } + + private static class DataInspectorVillagers implements DataInspector { + + ResourceLocation entityVillager = getKey("EntityVillager"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); + + convertItem(nbttagcompound2, "buy", sourceVer, targetVer); + convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); + convertItem(nbttagcompound2, "sell", sourceVer, targetVer); + nbttaglist.set(j, nbttagcompound2); + } + } + } + + return cmp; + } + + } + + private static class DataInspectorMobSpawnerMinecart implements DataInspector { + + ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { + cmp.putString("id", tileEntityMobSpawner.toString()); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", s); + } + + return cmp; + } + + } + + private static class DataInspectorMobSpawnerMobs implements DataInspector { + + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttaglist.getCompound(j); + + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + convertCompound(LegacyType.ENTITY, cmp, "SpawnData", sourceVer, targetVer); + } + + return cmp; + } + + } + + private static class DataInspectorCommandBlock implements DataInspector { + + ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightFakePlayer.java new file mode 100644 index 000000000..33656c5f8 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightFakePlayer.java @@ -0,0 +1,103 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1; + +import com.mojang.authlib.GameProfile; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.Stat; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.phys.Vec3; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +import java.util.OptionalInt; +import java.util.UUID; + +class PaperweightFakePlayer extends ServerPlayer { + + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile( + UUID.nameUUIDFromBytes("worldedit".getBytes()), + "[WorldEdit]" + ); + private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + + PaperweightFakePlayer(ServerLevel world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); + } + + @Override + public Vec3 position() { + return ORIGIN; + } + + @Override + public void tick() { + } + + @Override + public void die(DamageSource damagesource) { + } + + @Override + public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { + return this; + } + + @Override + public OptionalInt openMenu(MenuProvider factory) { + return OptionalInt.empty(); + } + + @Override + public void updateOptions(ServerboundClientInformationPacket packet) { + } + + @Override + public void displayClientMessage(Component message, boolean actionBar) { + } + + @Override + public void sendMessage(Component message, ChatType type, UUID sender) { + } + + @Override + public void awardStat(Stat stat, int amount) { + } + + @Override + public void awardStat(Stat stat) { + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } + + @Override + public void openTextEdit(SignBlockEntity sign) { + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightWorldNativeAccess.java new file mode 100644 index 000000000..82f13cfb7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_18_R1/PaperweightWorldNativeAccess.java @@ -0,0 +1,209 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Objects; + +public class PaperweightWorldNativeAccess implements + WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + + private final PaperweightAdapter adapter; + private final WeakReference world; + private SideEffectSet sideEffectSet; + + public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { + this.adapter = adapter; + this.world = world; + } + + private ServerLevel getWorld() { + return Objects.requireNonNull(world.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getWorld().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { + int stateId = BlockStateIdAccess.getBlockStateId(state); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { + return chunk.getBlockState(position); + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk chunk, + BlockPos position, + net.minecraft.world.level.block.state.BlockState state + ) { + return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState block, + BlockPos position + ) { + return Block.updateFromNeighbourShapes(block, getWorld(), position); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos position) { + getWorld().getChunkSource().getLightEngine().checkBlock(position); + } + + @Override + public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { + return false; + } + + @Override + public void notifyBlockUpdate( + LevelChunk chunk, + BlockPos position, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk chunk) { + return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); + } + + @Override + public void markBlockChanged(LevelChunk chunk, BlockPos position) { + if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { + getWorld().getChunkSource().blockChanged(position); + } + } + + @Override + public void notifyNeighbors( + BlockPos pos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + ServerLevel world = getWorld(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + world.updateNeighborsAt(pos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + Block block = oldState.getBlock(); + fireNeighborChanged(pos, world, block, pos.west()); + fireNeighborChanged(pos, world, block, pos.east()); + fireNeighborChanged(pos, world, block, pos.below()); + fireNeighborChanged(pos, world, block, pos.above()); + fireNeighborChanged(pos, world, block, pos.north()); + fireNeighborChanged(pos, world, block, pos.south()); + } + if (newState.hasAnalogOutputSignal()) { + world.updateNeighbourForOutputSignal(pos, newState.getBlock()); + } + } + + private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { + world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); + } + + @Override + public void updateNeighbors( + BlockPos pos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + ServerLevel world = getWorld(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = world.getWorld(); + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), + CraftBlockData.fromData(newState) + ); + world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange( + BlockPos pos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getWorld().onBlockStateChange(pos, oldState, newState); + } + + @Override + public void flush() { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightBlockMaterial.java new file mode 100644 index 000000000..aa72fa9a7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightBlockMaterial.java @@ -0,0 +1,189 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.util.ReflectionUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.EmptyBlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.PushReaction; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; + +public class PaperweightBlockMaterial implements BlockMaterial { + + private final Block block; + private final BlockState blockState; + private final Material material; + private final boolean isTranslucent; + private final CraftBlockData craftBlockData; + private final org.bukkit.Material craftMaterial; + private final int opacity; + private final CompoundTag tile; + + public PaperweightBlockMaterial(Block block) { + this(block, block.defaultBlockState()); + } + + public PaperweightBlockMaterial(Block block, BlockState blockState) { + this.block = block; + this.blockState = blockState; + this.material = blockState.getMaterial(); + this.craftBlockData = CraftBlockData.fromData(blockState); + this.craftMaterial = craftBlockData.getMaterial(); + BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName( + "properties", "aP")); + this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, + Refraction.pickName("canOcclude", "n") + ); + opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); + BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( + BlockPos.ZERO, + blockState + ); + tile = tileEntity == null + ? null + : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + } + + public Block getBlock() { + return block; + } + + public BlockState getState() { + return blockState; + } + + public CraftBlockData getCraftBlockData() { + return craftBlockData; + } + + public Material getMaterial() { + return material; + } + + @Override + public boolean isAir() { + return blockState.isAir(); + } + + @Override + public boolean isFullCube() { + return craftMaterial.isOccluding(); + } + + @Override + public boolean isOpaque() { + return material.isSolidBlocking(); + } + + @Override + public boolean isPowerSource() { + return blockState.isSignalSource(); + } + + @Override + public boolean isLiquid() { + return material.isLiquid(); + } + + @Override + public boolean isSolid() { + return material.isSolid(); + } + + @Override + public float getHardness() { + return craftBlockData.getState().destroySpeed; + } + + @Override + public float getResistance() { + return block.getExplosionResistance(); + } + + @Override + public float getSlipperiness() { + return block.getFriction(); + } + + @Override + public int getLightValue() { + return blockState.getLightEmission(); + } + + @Override + public int getLightOpacity() { + return opacity; + } + + @Override + public boolean isFragileWhenPushed() { + return material.getPushReaction() == PushReaction.DESTROY; + } + + @Override + public boolean isUnpushable() { + return material.getPushReaction() == PushReaction.BLOCK; + } + + @Override + public boolean isTicksRandomly() { + return block.isRandomlyTicking(blockState); + } + + @Override + public boolean isMovementBlocker() { + return material.isSolid(); + } + + @Override + public boolean isBurnable() { + return material.isFlammable(); + } + + @Override + public boolean isToolRequired() { + // Removed in 1.16.1, this is not present in higher versions + return false; + } + + @Override + public boolean isReplacedDuringPlacement() { + return material.isReplaceable(); + } + + @Override + public boolean isTranslucent() { + return isTranslucent; + } + + @Override + public boolean hasContainer() { + return block instanceof EntityBlock; + } + + @Override + public boolean isTile() { + return block instanceof EntityBlock; + } + + @Override + public CompoundTag getDefaultTile() { + return tile; + } + + @Override + public int getMapColor() { + // rgb field + return material.getColor().col; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweAdapter.java new file mode 100644 index 000000000..a5b24b387 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweAdapter.java @@ -0,0 +1,689 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.entity.LazyBaseEntity; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1.PaperweightAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.regen.PaperweightRegen; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.nbt.BinaryTag; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.WritableRegistry; +import net.minecraft.nbt.IntTag; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.TreeType; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_18_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_18_R1.CraftServer; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey; +import org.bukkit.entity.Player; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements + IDelegateBukkitImplAdapter { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final PaperweightAdapter parent; + // ------------------------------------------------------------------------ + // Code that may break between versions of Minecraft + // ------------------------------------------------------------------------ + private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); + private char[] ibdToStateOrdinal = null; + private int[] ordinalToIbdID = null; + private boolean initialised = false; + private Map>> allBlockProperties = null; + + public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { + this.parent = new PaperweightAdapter(); + } + + @Nullable + private static String getEntityId(Entity entity) { + ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType()); + return resourceLocation == null ? null : resourceLocation.toString(); + } + + private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + entity.save(compoundTag); + } + + @Override + public BukkitImplAdapter getParent() { + return parent; + } + + private synchronized boolean init() { + if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { + return false; + } + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size + for (int i = 0; i < ibdToStateOrdinal.length; i++) { + BlockState blockState = BlockTypesCache.states[i]; + PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial(); + int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState()); + char ordinal = blockState.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; + } + Map>> properties = new HashMap<>(); + try { + for (Field field : BlockStateProperties.class.getDeclaredFields()) { + Object obj = field.get(null); + if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property state)) { + continue; + } + Property property; + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + property = new BooleanProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else if (state instanceof DirectionProperty) { + property = new DirectionalProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase())) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + property = new EnumProperty( + state.getName(), + state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .collect(Collectors.toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + property = new IntegerProperty( + state.getName(), + (List) ImmutableList.copyOf(state.getPossibleValues()) + ); + } else { + throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> { + if (v == null) { + v = new ArrayList<>(Collections.singletonList(property)); + } else { + v.add(property); + } + return v; + }); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } finally { + allBlockProperties = ImmutableMap.copyOf(properties); + } + initialised = true; + return true; + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = getBlock(blockType); + return new PaperweightBlockMaterial(block); + } + + @Override + public synchronized BlockMaterial getMaterial(BlockState state) { + net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); + return new PaperweightBlockMaterial(blockState.getBlock(), blockState); + } + + public Block getBlock(BlockType blockType) { + return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); + } + + @Deprecated + @Override + public BlockState getBlock(Location location) { + Preconditions.checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + return state; + } + + @Override + public BaseBlock getFullBlock(final Location location) { + Preconditions.checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + final BlockPos blockPos = new BlockPos(x, y, z); + final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); + BlockState state = adapt(blockData); + if (state == null) { + org.bukkit.block.Block bukkitBlock = location.getBlock(); + state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + if (state.getBlockType().getMaterial().hasContainer()) { + + // Read the NBT data + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + } + } + + return state.toBaseBlock(); + } + + @Override + public Set getSupportedSideEffects() { + return SideEffectSet.defaults().getSideEffectsToApply(); + } + + public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { + CraftChunk craftChunk = (CraftChunk) chunk; + LevelChunk levelChunk = craftChunk.getHandle(); + Level level = levelChunk.getLevel(); + + BlockPos blockPos = new BlockPos(x, y, z); + net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + int y4 = y >> 4; + LevelChunkSection section = levelChunkSections[y4]; + + net.minecraft.world.level.block.state.BlockState existing; + if (section == null) { + existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); + } else { + existing = section.getBlockState(x & 15, y & 15, z & 15); + } + + levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity + + CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; + if (compoundTag != null || existing instanceof TileEntityBlock) { + level.setBlock(blockPos, blockState, 0); + // remove tile + if (compoundTag != null) { + // We will assume that the tile entity was created for us, + // though we do not do this on the Forge version + BlockEntity blockEntity = level.getBlockEntity(blockPos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + blockEntity.load(tag); // readTagIntoTileEntity - load data + } + } + } else { + if (existing == blockState) { + return true; + } + levelChunk.setBlockState(blockPos, blockState, false); + } + if (update) { + level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0); + } + return true; + } + + @Override + public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + return new PaperweightFaweWorldNativeAccess( + this, + new WeakReference<>(((CraftWorld) world).getHandle()) + ); + } + + @Override + public BaseEntity getEntity(org.bukkit.entity.Entity entity) { + Preconditions.checkNotNull(entity); + + CraftEntity craftEntity = ((CraftEntity) entity); + Entity mcEntity = craftEntity.getHandle(); + + String id = getEntityId(mcEntity); + + if (id != null) { + EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); + Supplier saveTag = () -> { + final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + readEntityIntoTag(mcEntity, minecraftTag); + //add Id for AbstractChangeSet to work + final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); + final Map tags = new HashMap<>(); + tag.keySet().forEach(key -> tags.put(key, tag.get(key))); + tags.put("Id", StringBinaryTag.of(id)); + return CompoundBinaryTag.from(tags); + }; + return new LazyBaseEntity(type, saveTag); + } else { + return null; + } + } + + @Override + public Component getRichBlockName(BlockType blockType) { + return parent.getRichBlockName(blockType); + } + + @Override + public Component getRichItemName(ItemType itemType) { + return parent.getRichItemName(itemType); + } + + @Override + public Component getRichItemName(BaseItemStack itemStack) { + return parent.getRichItemName(itemStack); + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); + return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); + } + + @Override + public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { + return BlockTypesCache.states[adaptToChar(blockState)]; + } + + public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { + int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + try { + init(); + return ibdToStateOrdinal[id]; + } catch (ArrayIndexOutOfBoundsException e1) { + LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", + blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 + ); + return BlockTypesCache.ReservedIDs.AIR; + } + } + } + + public char ibdIDToOrdinal(int id) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal[id]; + } + init(); + return ibdToStateOrdinal[id]; + } + } + + @Override + public char[] getIbdToStateOrdinal() { + if (initialised) { + return ibdToStateOrdinal; + } + synchronized (this) { + if (initialised) { + return ibdToStateOrdinal; + } + init(); + return ibdToStateOrdinal; + } + } + + public int ordinalToIbdID(char ordinal) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID[ordinal]; + } + init(); + return ordinalToIbdID[ordinal]; + } + } + + @Override + public int[] getOrdinalToIbdID() { + if (initialised) { + return ordinalToIbdID; + } + synchronized (this) { + if (initialised) { + return ordinalToIbdID; + } + init(); + return ordinalToIbdID; + } + } + + @Override + public > BlockData adapt(B state) { + PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); + return material.getCraftBlockData(); + } + + @Override + public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); + if (map != null && map.wasAccessibleSinceLastSave()) { + boolean flag = false; + // PlayerChunk.d players = map.players; + Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) + */ Stream.empty(); + + ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle(); + stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) + .forEach(entityPlayer -> { + synchronized (chunkPacket) { + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); + if (nmsPacket == null) { + nmsPacket = mapUtil.create(this, chunkPacket); + chunkPacket.setNativePacket(nmsPacket); + } + try { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(true); + entityPlayer.connection.send(nmsPacket); + } finally { + FaweCache.INSTANCE.CHUNK_FLAG.get().set(false); + } + } + }); + } + } + + @Override + public Map> getProperties(BlockType blockType) { + return getParent().getProperties(blockType); + } + + @Override + public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + int internalId = BlockStateIdAccess.getBlockStateId(blockState); + net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); + return blockState1.hasPostProcess( + ((CraftWorld) world).getHandle(), + new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) + ); + } + + @Override + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + ItemStack stack = new ItemStack( + Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), + baseItemStack.getAmount() + ); + stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); + return CraftItemStack.asCraftMirror(stack); + } + + @Override + public boolean generateTree( + TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3, + org.bukkit.World bukkitWorld + ) { + TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); + if (bukkitType == TreeType.CHORUS_PLANT) { + blockVector3 = blockVector3.add( + 0, + 1, + 0 + ); // bukkit skips the feature gen which does this offset normally, so we have to add it back + } + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType); + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + if (!grownTree) { + serverLevel.capturedBlockStates.clear(); + return false; + } else { + for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) { + if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { + continue; + } + editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(), + BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) + ); + } + + serverLevel.capturedBlockStates.clear(); + return true; + } + } + + @Override + public List getEntities(org.bukkit.World world) { + // Quickly add each entity to a list copy. + List mcEntities = new ArrayList<>(); + ((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add); + + List list = new ArrayList<>(); + mcEntities.forEach((mcEnt) -> { + org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity(); + if (bukkitEntity.isValid()) { + list.add(bukkitEntity); + } + + }); + return list; + } + + @Override + public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { + final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); + weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); + return weStack; + } + + @Override + public Tag toNative(net.minecraft.nbt.Tag foreign) { + return parent.toNative(foreign); + } + + @Override + public net.minecraft.nbt.Tag fromNative(Tag foreign) { + if (foreign instanceof PaperweightLazyCompoundTag) { + return ((PaperweightLazyCompoundTag) foreign).get(); + } + return parent.fromNative(foreign); + } + + @Override + public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); + } + + @Override + public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + return new PaperweightGetBlocks(world, chunkX, chunkZ); + } + + @Override + public int getInternalBiomeId(BiomeType biomeType) { + if (biomeType.getId().startsWith("minecraft:")) { + Biome biomeBase = CraftBlock.biomeToBiomeBase( + MinecraftServer.getServer().registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY), + BukkitAdapter.adapt(biomeType) + ); + return MinecraftServer.getServer().registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biomeBase); + } else { + WritableRegistry biomeRegistry = MinecraftServer.getServer().registryAccess() + .ownedRegistryOrThrow(Registry.BIOME_REGISTRY); + + ResourceLocation resourceLocation = biomeRegistry.keySet().stream() + .filter(resource -> resource.toString().equals(biomeType.getId())) + .findAny().orElse(null); + + return biomeRegistry.getId(biomeRegistry.get(resourceLocation)); + } + } + + @Override + public Iterable getRegisteredBiomes() { + WritableRegistry biomeRegistry = ((CraftServer) Bukkit.getServer()) + .getServer() + .registryAccess() + .ownedRegistryOrThrow( + Registry.BIOME_REGISTRY); + return biomeRegistry.stream() + .map(biomeRegistry::getKey) + .map(CraftNamespacedKey::fromMinecraft) + .collect(Collectors.toList()); + } + + @Override + public RelighterFactory getRelighterFactory() { + try { + Class.forName("ca.spottedleaf.starlight.common.light.StarLightEngine"); + if (PaperweightStarlightRelighter.isUsable()) { + return new PaperweightStarlightRelighterFactory(); + } + } catch (ThreadDeath td) { + throw td; + } catch (Throwable ignored) { + + } + return new NMSRelighterFactory(); + } + + @Override + public Map>> getAllProperties() { + if (initialised) { + return allBlockProperties; + } + synchronized (this) { + if (initialised) { + return allBlockProperties; + } + init(); + return allBlockProperties; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweWorldNativeAccess.java new file mode 100644 index 000000000..ac24e82d0 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightFaweWorldNativeAccess.java @@ -0,0 +1,286 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.math.IntPair; +import com.fastasyncworldedit.core.util.TaskManager; +import com.fastasyncworldedit.core.util.task.RunnableVal; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import com.sk89q.worldedit.world.block.BlockState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; +import org.bukkit.event.block.BlockPhysicsEvent; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + + private static final int UPDATE = 1; + private static final int NOTIFY = 2; + private static final Direction[] NEIGHBOUR_ORDER = { + Direction.EAST, + Direction.WEST, + Direction.DOWN, + Direction.UP, + Direction.NORTH, + Direction.SOUTH + }; + private final PaperweightFaweAdapter paperweightFaweAdapter; + private final WeakReference level; + private final AtomicInteger lastTick; + private final Set cachedChanges = new HashSet<>(); + private final Set cachedChunksToSend = new HashSet<>(); + private SideEffectSet sideEffectSet; + + public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { + this.paperweightFaweAdapter = paperweightFaweAdapter; + this.level = level; + // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. + // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. + this.lastTick = new AtomicInteger(MinecraftServer.currentTick); + } + + private Level getLevel() { + return Objects.requireNonNull(level.get(), "The reference to the world was lost"); + } + + @Override + public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public LevelChunk getChunk(int x, int z) { + return getLevel().getChunk(x, z); + } + + @Override + public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { + int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); + return BlockStateIdAccess.isValidInternalId(stateId) + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); + } + + @Override + public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { + return levelChunk.getBlockState(blockPos); + } + + @Nullable + @Override + public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + int currentTick = MinecraftServer.currentTick; + if (Fawe.isMainThread()) { + return levelChunk.setBlockState(blockPos, blockState, + this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) + ); + } + // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) + cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); + cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); + boolean nextTick = lastTick.get() > currentTick; + if (nextTick || cachedChanges.size() >= 1024) { + if (nextTick) { + lastTick.set(currentTick); + } + flushAsync(nextTick); + } + return blockState; + } + + @Override + public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( + net.minecraft.world.level.block.state.BlockState blockState, + BlockPos blockPos + ) { + return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); + } + + @Override + public BlockPos getPosition(int x, int y, int z) { + return new BlockPos(x, y, z); + } + + @Override + public void updateLightingForBlock(BlockPos blockPos) { + getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); + } + + @Override + public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + // We will assume that the tile entity was created for us, + // though we do not do this on the other versions + BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); + if (blockEntity == null) { + return false; + } + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); + blockEntity.load((CompoundTag) nativeTag); + return true; + } + + @Override + public void notifyBlockUpdate( + LevelChunk levelChunk, BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); + } + } + + @Override + public boolean isChunkTicking(LevelChunk levelChunk) { + return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); + } + + @Override + public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { + if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { + ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); + } + } + + @Override + public void notifyNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + Level level = getLevel(); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + level.blockUpdated(blockPos, oldState.getBlock()); + } else { + // When we don't want events, manually run the physics without them. + // Un-nest neighbour updating + for (Direction direction : NEIGHBOUR_ORDER) { + BlockPos shifted = blockPos.relative(direction); + level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); + } + } + if (newState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); + } + } + + @Override + public void updateNeighbors( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState, + int recursionLimit + ) { + Level level = getLevel(); + // a == updateNeighbors + // b == updateDiagonalNeighbors + oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { + CraftWorld craftWorld = level.getWorld(); + if (craftWorld != null) { + BlockPhysicsEvent event = new BlockPhysicsEvent( + craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), + CraftBlockData.fromData(newState) + ); + level.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + } + newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); + newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); + } + + @Override + public void onBlockStateChange( + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState oldState, + net.minecraft.world.level.block.state.BlockState newState + ) { + getLevel().onBlockStateChange(blockPos, oldState, newState); + } + + private synchronized void flushAsync(final boolean sendChunks) { + final Set changes = Set.copyOf(cachedChanges); + cachedChanges.clear(); + final Set toSend; + if (sendChunks) { + toSend = Set.copyOf(cachedChunksToSend); + cachedChunksToSend.clear(); + } else { + toSend = Collections.emptySet(); + } + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + if (!sendChunks) { + return; + } + for (IntPair chunk : toSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false); + } + } + }; + TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal)); + } + + @Override + public synchronized void flush() { + RunnableVal runnableVal = new RunnableVal<>() { + @Override + public void run(Object value) { + cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, + sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) + )); + for (IntPair chunk : cachedChunksToSend) { + PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false); + } + } + }; + if (Fawe.isMainThread()) { + runnableVal.run(); + } else { + TaskManager.taskManager().sync(runnableVal); + } + cachedChanges.clear(); + cachedChunksToSend.clear(); + } + + private record CachedChange( + LevelChunk levelChunk, + BlockPos blockPos, + net.minecraft.world.level.block.state.BlockState blockState + ) { + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java new file mode 100644 index 000000000..897001e45 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java @@ -0,0 +1,1112 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.queue.implementation.QueueHandler; +import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; +import com.fastasyncworldedit.core.util.collection.AdaptedMap; +import com.google.common.base.Suppliers; +import com.google.common.collect.Iterables; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import io.papermc.paper.event.block.BeaconDeactivatedEvent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.nbt.IntTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.entity.BeaconBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); + private static final Function nmsTile2We = + tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin + .getInstance() + .getBukkitImplAdapter()); + private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); + private final ServerLevel serverLevel; + private final int chunkX; + private final int chunkZ; + private final int minHeight; + private final int maxHeight; + private final int minSectionPosition; + private final int maxSectionPosition; + private final Registry biomeRegistry; + private LevelChunkSection[] sections; + private LevelChunk levelChunk; + private DataLayer[] blockLight; + private DataLayer[] skyLight; + private boolean createCopy = false; + private PaperweightGetBlocks_Copy copy = null; + private boolean forceLoadSections = true; + private boolean lightUpdate = false; + + public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { + this(((CraftWorld) world).getHandle(), chunkX, chunkZ); + } + + public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { + super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); + this.serverLevel = serverLevel; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + this.minHeight = serverLevel.getMinBuildHeight(); + this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.minSectionPosition = minHeight >> 4; + this.maxSectionPosition = maxHeight >> 4; + this.skyLight = new DataLayer[getSectionCount()]; + this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + } + + public int getChunkX() { + return chunkX; + } + + public int getChunkZ() { + return chunkZ; + } + + @Override + public boolean isCreateCopy() { + return createCopy; + } + + @Override + public void setCreateCopy(boolean createCopy) { + this.createCopy = createCopy; + } + + @Override + public IChunkGet getCopy() { + return copy; + } + + @Override + public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { + if (light != null) { + lightUpdate = true; + try { + fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256); + bitArray.fromRaw(data); + Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); + Heightmap heightMap = getChunk().heightmaps.get(nativeType); + heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Biome biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( + sectionPos); + if (dataLayer != null) { + lightUpdate = true; + synchronized (dataLayer) { + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + if (sky) { + SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer1 = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.SKY) + .getDataLayerData(sectionPos1); + if (dataLayer1 != null) { + lightUpdate = true; + synchronized (dataLayer1) { + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); + } + } + } + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( + chunkX << 4), y, (z & 15) + ( + chunkZ << 4))); + if (blockEntity == null) { + return null; + } + return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + } + + @Override + public Map getTiles() { + Map nmsTiles = getChunk().getBlockEntities(); + if (nmsTiles.isEmpty()) { + return Collections.emptyMap(); + } + return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); + } + + @Override + public int getSkyLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (skyLight[alayer] == null) { + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = + serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); + // If the server hasn't generated the section's NibbleArray yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + LightLayer.BLOCK, + sectionPos, + dataLayer, + true + ); + } + skyLight[alayer] = dataLayer; + } + return skyLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int getEmittedLight(int x, int y, int z) { + int layer = y >> 4; + int alayer = layer - getMinSectionPosition(); + if (blockLight[alayer] == null) { + serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); + SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); + DataLayer dataLayer = serverLevel + .getChunkSource() + .getLightEngine() + .getLayerListener(LightLayer.BLOCK) + .getDataLayerData(sectionPos); + // If the server hasn't generated the section's DataLayer yet, it will be null + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. + Arrays.fill(LAYER_COUNT, (byte) 15); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, + dataLayer, true + ); + } + blockLight[alayer] = dataLayer; + } + return blockLight[alayer].get(x & 15, y & 15, z & 15); + } + + @Override + public int[] getHeightMap(HeightMapType type) { + long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); + BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); + return bitArray.toRaw(new int[256]); + } + + @Override + public CompoundTag getEntity(UUID uuid) { + Entity entity = serverLevel.getEntity(uuid); + if (entity != null) { + org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); + return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + } + for (List entry : /*getChunk().getEntitySlices()*/ new List[0]) { + if (entry != null) { + for (Entity ent : entry) { + if (uuid.equals(ent.getUUID())) { + org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity(); + return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); + } + } + } + } + return null; + } + + @Override + public Set getEntities() { + List[] slices = /*getChunk().getEntitySlices()*/ new List[0]; + int size = 0; + for (List slice : slices) { + if (slice != null) { + size += slice.size(); + } + } + if (slices.length == 0) { + return Collections.emptySet(); + } + int finalSize = size; + return new AbstractSet() { + @Override + public int size() { + return finalSize; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object get) { + if (!(get instanceof CompoundTag getTag)) { + return false; + } + Map value = getTag.getValue(); + CompoundTag getParts = (CompoundTag) value.get("UUID"); + UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least")); + for (List slice : slices) { + if (slice != null) { + for (Entity entity : slice) { + UUID uuid = entity.getUUID(); + if (uuid.equals(getUUID)) { + return true; + } + } + } + } + return false; + } + + @NotNull + @Override + public Iterator iterator() { + Iterable result = StreamSupport.stream(Iterables.concat(slices).spliterator(), false).map(input -> { + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + return (CompoundTag) adapter.toNative(input.saveWithoutId(tag)); + }).collect(Collectors.toList()); + return result.iterator(); + } + }; + } + + private void removeEntity(Entity entity) { + entity.discard(); + } + + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { + return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); + } + + @Override + public synchronized > T call(IChunkSet set, Runnable finalizer) { + forceLoadSections = false; + copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null; + try { + ServerLevel nmsWorld = serverLevel; + LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); + boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE; + + // Remove existing tiles. Create a copy so that we can remove blocks + Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); + List beacons = null; + if (!chunkTiles.isEmpty()) { + for (Map.Entry entry : chunkTiles.entrySet()) { + final BlockPos pos = entry.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int layer = ly >> 4; + if (!set.hasSection(layer)) { + continue; + } + + int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); + if (ordinal != 0) { + BlockEntity tile = entry.getValue(); + if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { + if (beacons == null) { + beacons = new ArrayList<>(); + } + beacons.add(tile); + PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); + continue; + } + nmsChunk.removeBlockEntity(tile.getBlockPos()); + if (createCopy) { + copy.storeTile(tile); + } + } + } + } + final BiomeType[][] biomes = set.getBiomes(); + + int bitMask = 0; + synchronized (nmsChunk) { + LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); + + for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { + + int getSectionIndex = layerNo - getMinSectionPosition(); + int setSectionIndex = layerNo - set.getMinSectionPosition(); + + if (!set.hasSection(layerNo)) { + // No blocks, but might be biomes present. Handle this lazily. + if (biomes == null) { + continue; + } + if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { + continue; + } + if (biomes[setSectionIndex] != null) { + synchronized (super.sectionLocks[getSectionIndex]) { + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + if (createCopy && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); + } + + if (existingSection == null) { + PalettedContainer biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeRegistry + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + fastmode, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, getSectionIndex)) { + updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } else { + PalettedContainer biomeData = existingSection.getBiomes(); + setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); + } + } + } + continue; + } + + bitMask |= 1 << getSectionIndex; + + char[] tmp = set.load(layerNo); + char[] setArr = new char[4096]; + System.arraycopy(tmp, 0, setArr, 0, 4096); + + // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was + // submitted to keep loaded internal chunks to queue target size. + synchronized (super.sectionLocks[getSectionIndex]) { + + LevelChunkSection newSection; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; + + if (createCopy) { + char[] tmpLoad = loadPrivately(layerNo); + char[] copyArr = new char[4096]; + System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); + copy.storeSection(getSectionIndex, copyArr); + if (biomes != null && existingSection != null) { + copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); + } + } + + if (existingSection == null) { + PalettedContainer biomeData = biomes == null ? new PalettedContainer<>( + biomeRegistry, + biomeRegistry.getOrThrow(Biomes.PLAINS), + PalettedContainer.Strategy.SECTION_BIOMES, + null + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeRegistry); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + fastmode, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, getSectionIndex)) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + continue; + } else { + existingSection = levelChunkSections[getSectionIndex]; + if (existingSection == null) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + continue; + } + } + } + PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0); + + //ensure that the server doesn't try to tick the chunksection while we're editing it. + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + + synchronized (lock) { + // lock.acquire(); + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = null; + this.reset(); + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; + this.reset(); + } else if (!Arrays.equals(update(getSectionIndex, new char[4096], true), loadPrivately(layerNo))) { + this.reset(layerNo); + /*} else if (lock.isModified()) { + this.reset(layerNo);*/ + } + } finally { + sectionLock.writeLock().unlock(); + } + + PalettedContainer biomeData = existingSection.getBiomes(); + + if (biomes != null && biomes[setSectionIndex] != null) { + setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); + } + + newSection = + PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + fastmode, + adapter, + biomeRegistry, + biomeData + ); + if (!PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + existingSection, + newSection, + getSectionIndex + )) { + LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, + getSectionIndex + ); + } else { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); + } + } + } + } + + Map heightMaps = set.getHeightMaps(); + for (Map.Entry entry : heightMaps.entrySet()) { + PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); + } + PaperweightGetBlocks.this.setLightingToGet( + set.getLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + PaperweightGetBlocks.this.setSkyLightingToGet( + set.getSkyLight(), + set.getMinSectionPosition(), + set.getMaxSectionPosition() + ); + + Runnable[] syncTasks = null; + + int bx = chunkX << 4; + int bz = chunkZ << 4; + + // Call beacon deactivate events here synchronously + // list will be null on spigot, so this is an implicit isPaper check + if (beacons != null && !beacons.isEmpty()) { + final List finalBeacons = beacons; + + syncTasks = new Runnable[4]; + + syncTasks[3] = () -> { + for (BlockEntity beacon : finalBeacons) { + BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); + new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); + } + }; + } + + Set entityRemoves = set.getEntityRemoves(); + if (entityRemoves != null && !entityRemoves.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[3]; + } + + syncTasks[2] = () -> { + final List[] entities = /*nmsChunk.e()*/ new List[0]; + + for (final Collection ents : entities) { + if (!ents.isEmpty()) { + final Iterator iter = ents.iterator(); + while (iter.hasNext()) { + final Entity entity = iter.next(); + if (entityRemoves.contains(entity.getUUID())) { + if (createCopy) { + copy.storeEntity(entity); + } + iter.remove(); + removeEntity(entity); + } + } + } + } + }; + } + + Set entities = set.getEntities(); + if (entities != null && !entities.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[2]; + } + + syncTasks[1] = () -> { + for (final CompoundTag nativeTag : entities) { + final Map entityTagMap = nativeTag.getValue(); + final StringTag idTag = (StringTag) entityTagMap.get("Id"); + final ListTag posTag = (ListTag) entityTagMap.get("Pos"); + final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); + if (idTag == null || posTag == null || rotTag == null) { + LOGGER.error("Unknown entity tag: {}", nativeTag); + continue; + } + final double x = posTag.getDouble(0); + final double y = posTag.getDouble(1); + final double z = posTag.getDouble(2); + final float yaw = rotTag.getFloat(0); + final float pitch = rotTag.getFloat(1); + final String id = idTag.getValue(); + + EntityType type = EntityType.byString(id).orElse(null); + if (type != null) { + Entity entity = type.create(nmsWorld); + if (entity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + entity.load(tag); + entity.absMoveTo(x, y, z, yaw, pitch); + nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + } + } + }; + + } + + // set tiles + Map tiles = set.getTiles(); + if (tiles != null && !tiles.isEmpty()) { + if (syncTasks == null) { + syncTasks = new Runnable[1]; + } + + syncTasks[0] = () -> { + for (final Map.Entry entry : tiles.entrySet()) { + final CompoundTag nativeTag = entry.getValue(); + final BlockVector3 blockHash = entry.getKey(); + final int x = blockHash.getX() + bx; + final int y = blockHash.getY(); + final int z = blockHash.getZ() + bz; + final BlockPos pos = new BlockPos(x, y, z); + + synchronized (nmsWorld) { + BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); + if (tileEntity == null || tileEntity.isRemoved()) { + nmsWorld.removeBlockEntity(pos); + tileEntity = nmsWorld.getBlockEntity(pos); + } + if (tileEntity != null) { + final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( + nativeTag); + tag.put("x", IntTag.valueOf(x)); + tag.put("y", IntTag.valueOf(y)); + tag.put("z", IntTag.valueOf(z)); + tileEntity.load(tag); + } + } + } + }; + } + + Runnable callback; + if (bitMask == 0 && biomes == null && !lightUpdate) { + callback = null; + } else { + int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; + boolean finalLightUpdate = lightUpdate; + callback = () -> { + // Set Modified + nmsChunk.setLightCorrect(true); // Set Modified + nmsChunk.mustNotSave = false; + nmsChunk.setUnsaved(true); + // send to player + if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { + this.send(finalMask, finalLightUpdate); + } + if (finalizer != null) { + finalizer.run(); + } + }; + } + if (syncTasks != null) { + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); + Runnable[] finalSyncTasks = syncTasks; + + // Chain the sync tasks and the callback + Callable chain = () -> { + try { + // Run the sync tasks + for (Runnable task : finalSyncTasks) { + if (task != null) { + task.run(); + } + } + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + return null; + } else { + return queueHandler.async(callback, null); + } + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + }; + //noinspection unchecked - required at compile time + return (T) (Future) queueHandler.sync(chain); + } else { + if (callback == null) { + if (finalizer != null) { + finalizer.run(); + } + } else { + callback.run(); + } + } + } + return null; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } finally { + forceLoadSections = true; + } + } + + private void updateGet( + LevelChunk nmsChunk, + LevelChunkSection[] chunkSections, + LevelChunkSection section, + char[] arr, + int layer + ) { + try { + sectionLock.writeLock().lock(); + if (this.getChunk() != nmsChunk) { + this.levelChunk = nmsChunk; + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + this.reset(); + } + if (this.sections == null) { + this.sections = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); + } + if (this.sections[layer] != section) { + // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords + this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; + } + } finally { + sectionLock.writeLock().unlock(); + } + this.blocks[layer] = arr; + } + + private char[] loadPrivately(int layer) { + layer -= getMinSectionPosition(); + if (super.sections[layer] != null) { + synchronized (super.sectionLocks[layer]) { + if (super.sections[layer].isFull() && super.blocks[layer] != null) { + char[] blocks = new char[4096]; + System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096); + return blocks; + } + } + } + return PaperweightGetBlocks.this.update(layer, null, true); + } + + @Override + public synchronized void send(int mask, boolean lighting) { + PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); + } + + /** + * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this + * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation + * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. + * + * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) + * @param data array to be updated/filled with data or null + * @param aggressive if the cached section array should be re-acquired. + * @return the given array to be filled with data, or a new array if null is given. + */ + @Override + public char[] update(int layer, char[] data, boolean aggressive) { + LevelChunkSection section = getSections(aggressive)[layer]; + // Section is null, return empty array + if (section == null) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + return data; + } + if (data != null && data.length != 4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { + data = new char[4096]; + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); + } + DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); + synchronized (lock) { + // Efficiently convert ChunkSection to raw data + try { + lock.acquire(); + + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); + + if (bits instanceof ZeroBitStorage) { + Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper + return data; + } + + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); + + final int bitsPerEntry = bits.getBits(); + final long[] blockStates = bits.getRaw(); + + new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); + + int num_palette; + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + num_palette = palette.getSize(); + } else { + // The section's palette is the global block palette. + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char ordinal = adapter.ibdIDToOrdinal(paletteVal); + data[i] = ordinal; + } + return data; + } + + char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); + try { + if (num_palette != 1) { + for (int i = 0; i < num_palette; i++) { + char ordinal = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = ordinal; + } + for (int i = 0; i < 4096; i++) { + char paletteVal = data[i]; + char val = paletteToOrdinal[paletteVal]; + if (val == Character.MAX_VALUE) { + val = ordinal(palette.valueFor(i), adapter); + paletteToOrdinal[i] = val; + } + data[i] = val; + } + } else { + char ordinal = ordinal(palette.valueFor(0), adapter); + Arrays.fill(data, ordinal); + } + } finally { + for (int i = 0; i < num_palette; i++) { + paletteToOrdinal[i] = Character.MAX_VALUE; + } + } + return data; + } catch (IllegalAccessException | InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + lock.release(); + } + } + } + + private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) { + if (ibd == null) { + return BlockTypesCache.ReservedIDs.AIR; + } else { + return adapter.adaptToChar(ibd); + } + } + + public LevelChunkSection[] getSections(boolean force) { + force &= forceLoadSections; + sectionLock.readLock().lock(); + LevelChunkSection[] tmp = sections; + sectionLock.readLock().unlock(); + if (tmp == null || force) { + try { + sectionLock.writeLock().lock(); + tmp = sections; + if (tmp == null || force) { + LevelChunkSection[] chunkSections = getChunk().getSections(); + tmp = new LevelChunkSection[chunkSections.length]; + System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); + sections = tmp; + } + } finally { + sectionLock.writeLock().unlock(); + } + } + return tmp; + } + + public LevelChunk getChunk() { + LevelChunk levelChunk = this.levelChunk; + if (levelChunk == null) { + synchronized (this) { + levelChunk = this.levelChunk; + if (levelChunk == null) { + this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); + } + } + } + return levelChunk; + } + + private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { + for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { + if (light[Y] == null) { + continue; + } + SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); + DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( + sectionPos); + if (dataLayer == null) { + byte[] LAYER_COUNT = new byte[2048]; + Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); + dataLayer = new DataLayer(LAYER_COUNT); + ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( + lightLayer, + sectionPos, + dataLayer, + true + ); + } + synchronized (dataLayer) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int i = y << 8 | z << 4 | x; + if (light[Y][i] < 16) { + dataLayer.set(x, y, z, light[Y][i]); + } + } + } + } + } + } + } + + private void setBiomesToPalettedContainer( + final BiomeType[] biomes, + PalettedContainer data + ) { + int index = 0; + if (biomes == null) { + return; + } + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + data.set( + x, + y, + z, + biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId())) + ); + } + } + } + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return getSections(false)[layer] != null; + } + + @Override + public synchronized boolean trim(boolean aggressive) { + skyLight = new DataLayer[getSectionCount()]; + blockLight = new DataLayer[getSectionCount()]; + if (aggressive) { + sectionLock.writeLock().lock(); + sections = null; + levelChunk = null; + sectionLock.writeLock().unlock(); + return super.trim(true); + } else if (sections == null) { + // don't bother trimming if there are no sections stored. + return true; + } else { + for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { + int layer = i - getMinSectionPosition(); + if (!hasSection(i) || !super.sections[layer].isFull()) { + continue; + } + LevelChunkSection existing = getSections(true)[layer]; + try { + final PalettedContainer blocksExisting = existing.getStates(); + + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); + final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( + dataObject); + int paletteSize; + + if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { + paletteSize = palette.getSize(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; + } + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks_Copy.java new file mode 100644 index 000000000..fd0dadb03 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks_Copy.java @@ -0,0 +1,240 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; +import com.fastasyncworldedit.core.queue.IBlocks; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.google.common.base.Suppliers; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.PalettedContainer; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; + +public class PaperweightGetBlocks_Copy implements IChunkGet { + + private final Map tiles = new HashMap<>(); + private final Set entities = new HashSet<>(); + private final char[][] blocks; + private final int minHeight; + private final int maxHeight; + private final ServerLevel serverLevel; + private PalettedContainer[] biomes = null; + + protected PaperweightGetBlocks_Copy(ServerLevel world) { + this.serverLevel = world; + this.minHeight = world.getMinBuildHeight(); + this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. + this.blocks = new char[getSectionCount()][]; + } + + protected void storeTile(BlockEntity blockEntity) { + tiles.put( + BlockVector3.at( + blockEntity.getBlockPos().getX(), + blockEntity.getBlockPos().getY(), + blockEntity.getBlockPos().getZ() + ), + new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + ); + } + + @Override + public Map getTiles() { + return tiles; + } + + @Override + @Nullable + public CompoundTag getTile(int x, int y, int z) { + return tiles.get(BlockVector3.at(x, y, z)); + } + + protected void storeEntity(Entity entity) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag))); + } + + @Override + public Set getEntities() { + return this.entities; + } + + @Override + public CompoundTag getEntity(UUID uuid) { + for (CompoundTag tag : entities) { + UUID tagUUID; + if (tag.containsKey("UUID")) { + int[] arr = tag.getIntArray("UUID"); + tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL)); + } else if (tag.containsKey("UUIDMost")) { + tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast")); + } else if (tag.containsKey("PersistentIDMSB")) { + tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB")); + } else { + return null; + } + if (uuid.equals(tagUUID)) { + return tag; + } + } + return null; + } + + @Override + public boolean isCreateCopy() { + return false; + } + + @Override + public void setCreateCopy(boolean createCopy) { + } + + @Override + public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { + } + + @Override + public void setHeightmapToGet(HeightMapType type, int[] data) { + } + + @Override + public int getMaxY() { + return maxHeight; + } + + @Override + public int getMinY() { + return minHeight; + } + + @Override + public int getMaxSectionPosition() { + return maxHeight >> 4; + } + + @Override + public int getMinSectionPosition() { + return minHeight >> 4; + } + + @Override + public BiomeType getBiomeType(int x, int y, int z) { + Biome biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + return biome != null ? PaperweightPlatformAdapter.adapt(biome, serverLevel) : null; + } + + @Override + public void removeSectionLighting(int layer, boolean sky) { + } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + @Override + public int getSectionCount() { + return serverLevel.getSectionsCount(); + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; + } + + protected void storeBiomes(int layer, PalettedContainer biomeData) { + if (biomes == null) { + biomes = new PalettedContainer[getSectionCount()]; + } + biomes[layer] = biomeData; + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + BlockState state = BlockTypesCache.states[get(x, y, z)]; + return state.toBaseBlock(this, x, y, z); + } + + @Override + public boolean hasSection(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public char[] loadIfPresent(int layer) { + layer -= getMinSectionPosition(); + return blocks[layer]; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return BlockTypesCache.states[get(x, y, z)]; + } + + @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + + public char get(int x, int y, int z) { + final int layer = (y >> 4) - getMinSectionPosition(); + final int index = (y & 15) << 8 | z << 4 | x; + return blocks[layer][index]; + } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..5f59cc498 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightMapChunkUtil.java @@ -0,0 +1,35 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; + +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; + +//TODO un-very-break-this +public class PaperweightMapChunkUtil extends MapChunkUtil { + + public PaperweightMapChunkUtil() throws NoSuchFieldException { + fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); + fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); + fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); + fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); + fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); + fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); + fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); + fieldX.setAccessible(true); + fieldZ.setAccessible(true); + fieldBitMask.setAccessible(true); + fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); + fieldBlockEntities.setAccessible(true); + fieldFull.setAccessible(true); + } + + @Override + public ClientboundLevelChunkWithLightPacket createPacket() { + // TODO ??? return new ClientboundLevelChunkPacket(); + throw new UnsupportedOperationException(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..27e22a05c --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java @@ -0,0 +1,661 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; +import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweCache; +import com.fastasyncworldedit.core.math.BitArrayUnstretched; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.datafixers.util.Either; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import io.papermc.lib.PaperLib; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; +import net.minecraft.world.level.gameevent.GameEventDispatcher; +import net.minecraft.world.level.gameevent.GameEventListener; +import org.bukkit.craftbukkit.v1_18_R1.CraftChunk; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import sun.misc.Unsafe; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.function.Function; + +public final class PaperweightPlatformAdapter extends NMSAdapter { + + public static final Field fieldData; + + public static final Constructor dataConstructor; + + public static final Field fieldStorage; + public static final Field fieldPalette; + + + public static final Field fieldTickingFluidCount; + public static final Field fieldTickingBlockCount; + public static final Field fieldNonEmptyBlockCount; + + private static final MethodHandle methodGetVisibleChunk; + + private static final int CHUNKSECTION_BASE; + private static final int CHUNKSECTION_SHIFT; + + private static final Field fieldThreadingDetector; + private static final long fieldThreadingDetectorOffset; + + private static final Field fieldLock; + private static final long fieldLockOffset; + + private static final Field fieldGameEventDispatcherSections; + private static final MethodHandle methodremoveTickingBlockEntity; + + private static final Field fieldRemove; + + static { + try { + fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); + fieldData.setAccessible(true); + + Class dataClazz = fieldData.getType(); + dataConstructor = dataClazz.getDeclaredConstructors()[0]; + dataConstructor.setAccessible(true); + + fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); + fieldStorage.setAccessible(true); + fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); + fieldPalette.setAccessible(true); + + fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); + fieldNonEmptyBlockCount.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); + + Unsafe unsafe = ReflectionUtils.getUnsafe(); + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); + + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + + fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( + "gameEventDispatcherSections", "t")); + fieldGameEventDispatcherSections.setAccessible(true); + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "m" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); + fieldRemove.setAccessible(true); + + CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); + int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); + if ((scale & (scale - 1)) != 0) { + throw new Error("data type scale not a power of two"); + } + CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); + } catch (RuntimeException e) { + throw e; + } catch (Throwable rethrow) { + rethrow.printStackTrace(); + throw new RuntimeException(rethrow); + } + } + + static boolean setSectionAtomic( + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; + if (layer >= 0 && layer < sections.length) { + return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + } + return false; + } + + static DelegateSemaphore applyLock(LevelChunkSection section) { + try { + synchronized (section) { + Unsafe unsafe = ReflectionUtils.getUnsafe(); + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(blocks, + fieldThreadingDetectorOffset) ; + synchronized(currentThreadingDetector) { + Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + if (currentLock instanceof DelegateSemaphore) { + return (DelegateSemaphore) currentLock; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + return newLock; + } + } + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) { + if (!PaperLib.isPaper()) { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false); + if (nmsChunk != null) { + return nmsChunk; + } + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + } else { + LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + return nmsChunk; + } + // Avoid "async" methods from the main thread. + if (Fawe.isMainThread()) { + return serverLevel.getChunk(chunkX, chunkZ); + } + CompletableFuture future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); + try { + CraftChunk chunk = (CraftChunk) future.get(); + return chunk.getHandle(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { + ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; + try { + return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ)); + } catch (Throwable thr) { + throw new RuntimeException(thr); + } + } + + public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { + ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); + if (chunkHolder == null) { + return; + } + ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); + // UNLOADED_CHUNK + Optional optional = ((Either) chunkHolder + .getTickingChunkFuture() + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + optional = optional.or(() -> Optional.ofNullable(nmsWorld + .getChunkSource() + .getChunkAtIfLoadedImmediately(chunkX, chunkZ))); + } + if (optional.isEmpty()) { + return; + } + LevelChunk levelChunk = optional.get(); + TaskManager.taskManager().task(() -> { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true, + false // last false is to not bother with x-ray + ); + } else { + // deprecated on paper + //noinspection deprecation + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true + ); + } + nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); + }); + } + + private static List nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) { + return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false); + } + + /* + NMS conversion + */ + public static LevelChunkSection newChunkSection( + final int layer, final char[] blocks, boolean fastmode, + CachedBukkitAdapter adapter, Registry biomeRegistry, + @Nullable PalettedContainer biomes + ) { + return newChunkSection(layer, null, blocks, fastmode, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, final Function get, char[] set, + boolean fastmode, CachedBukkitAdapter adapter, Registry biomeRegistry, + @Nullable PalettedContainer biomes + ) { + if (set == null) { + return newChunkSection(layer, biomeRegistry, biomes); + } + final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); + final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); + final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); + final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); + try { + int[] num_palette_buffer = new int[1]; + Map ticking_blocks = new HashMap<>(); + int air; + if (get == null) { + air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, + set, ticking_blocks, fastmode, adapter + ); + } else { + air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, + num_palette_buffer, get, set, ticking_blocks, fastmode, adapter + ); + } + int num_palette = num_palette_buffer[0]; + // BlockStates + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + Object configuration = + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(new FakeIdMapBlock(num_palette), bitsPerEntry); + if (bitsPerEntry > 0 && bitsPerEntry < 5) { + bitsPerEntry = 4; + } else if (bitsPerEntry > 8) { + bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong); + + if (num_palette == 1) { + for (int i = 0; i < blockBitArrayEnd; i++) { + blockStates[i] = 0; + } + } else { + final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates); + bitArray.fromRaw(blocksCopy); + } + + final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); + final BitStorage nmsBits; + if (bitsPerEntry == 0) { + nmsBits = new ZeroBitStorage(4096); + } else { + nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); + } + final Palette blockStatePalette; + List palette; + if (bitsPerEntry < 9) { + palette = new ArrayList<>(); + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + final BlockState state = BlockTypesCache.states[ordinal]; + palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState()); + } + } else { + palette = List.of(); + } + + // Create palette with data + @SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot + final PalettedContainer blockStatePalettedContainer = + new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + PalettedContainer.Strategy.SECTION_STATES, + PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry), + nmsBits, + palette + ); + LevelChunkSection levelChunkSection; + try { + //fieldStorage.set(dataPaletteBlocks, nmsBits); + //fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer); + if (biomes == null) { + biomes = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.getOrThrow(Biomes.PLAINS), + PalettedContainer.Strategy.SECTION_BIOMES, + null + ); + } + levelChunkSection = new LevelChunkSection(layer, blockStatePalettedContainer, biomes); + setCount(ticking_blocks.size(), 4096 - air, levelChunkSection); + if (!fastmode) { + ticking_blocks.forEach((pos, ordinal) -> levelChunkSection.setBlockState( + pos.getBlockX(), + pos.getBlockY(), + pos.getBlockZ(), + Block.stateById(ordinal) + )); + } + } catch (final IllegalAccessException e) { + throw new RuntimeException(e); + } + + return levelChunkSection; + } catch (final Throwable e) { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; + } + } + + private static LevelChunkSection newChunkSection( + int layer, Registry biomeRegistry, + @Nullable PalettedContainer biomes + ) { + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES, + null + ); + PalettedContainer biomesPalette = biomes != null ? biomes : new PalettedContainer<>( + biomeRegistry, + biomeRegistry.getOrThrow(Biomes.PLAINS), + PalettedContainer.Strategy.SECTION_BIOMES, + null + ); + return new LevelChunkSection(layer, dataPaletteBlocks, biomesPalette); + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer getBiomePalettedContainer(BiomeType[] biomes, Registry biomeRegistry) { + if (biomes == null) { + return null; + } + // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length + Map palette = new HashMap<>(); + for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { + Biome biome; + if (biomeType == null) { + biome = biomeRegistry.getOrThrow(Biomes.PLAINS); + } else { + biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId())); + } + palette.put(biomeType, biome); + } + int biomeCount = palette.size(); + int bitsPerEntry = MathMan.log2nlz(biomeCount - 1); + Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration( + new FakeIdMapBiome(biomeCount), + bitsPerEntry + ); + if (bitsPerEntry > 3) { + bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); + } + PalettedContainer biomePalettedContainer = new PalettedContainer<>( + biomeRegistry, + biomeRegistry.getOrThrow(Biomes.PLAINS), + PalettedContainer.Strategy.SECTION_BIOMES, + null + ); + + final Palette biomePalette; + if (bitsPerEntry == 0) { + biomePalette = new SingleValuePalette<>( + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry == 4) { + biomePalette = LinearPalette.create( + 4, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else if (bitsPerEntry < 9) { + biomePalette = HashMapPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + new ArrayList<>(palette.values()) // Must be modifiable + ); + } else { + biomePalette = GlobalPalette.create( + bitsPerEntry, + biomePalettedContainer.registry, + biomePalettedContainer, + null // unused + ); + } + + int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes + final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero); + final int arrayLength = MathMan.ceilZero(64f / blocksPerLong); + + + BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage( + bitsPerEntry, + 64, + new long[arrayLength] + ); + + try { + Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette); + fieldData.set(biomePalettedContainer, data); + int index = 0; + for (int y = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = biomes[index]; + if (biomeType == null) { + continue; + } + Biome biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId())); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws + IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); // TODO FIXME + fieldTickingBlockCount.setShort(section, (short) tickingBlockCount); + fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount); + } + + public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) { + ResourceLocation resourceLocation = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getKey( + biome); + if (resourceLocation == null) { + return levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biome) == -1 + ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT)); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + // Do the method ourselves to avoid trying to reflect generic method parameters + // similar to removeGameEventListener + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + Block block = beacon.getBlockState().getBlock(); + if (block instanceof EntityBlock) { + GameEventListener gameEventListener = ((EntityBlock) block).getListener(levelChunk.level, beacon); + if (gameEventListener != null) { + int i = SectionPos.blockToSectionCoord(beacon.getBlockPos().getY()); + GameEventDispatcher gameEventDispatcher = levelChunk.getEventDispatcher(i); + gameEventDispatcher.unregister(gameEventListener); + if (gameEventDispatcher.isEmpty()) { + try { + ((Int2ObjectMap) fieldGameEventDispatcherSections.get(levelChunk)) + .remove(i); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static class FakeIdMapBlock implements IdMap { + + private final int size; + + FakeIdMapBlock(int size) { + this.size = size; + } + + @Override + public int getId(final net.minecraft.world.level.block.state.BlockState entry) { + return 0; + } + + @Nullable + @Override + public net.minecraft.world.level.block.state.BlockState byId(final int index) { + return null; + } + + @Override + public int size() { + return size; + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + static class FakeIdMapBiome implements IdMap { + + private final int size; + + FakeIdMapBiome(int size) { + this.size = size; + } + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Override + public int size() { + return size; + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighter.java new file mode 100644 index 000000000..999faecb0 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighter.java @@ -0,0 +1,238 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.core.configuration.Settings; +import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.queue.IQueueChunk; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.fastasyncworldedit.core.util.MathMan; +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.server.MCUtil; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.TicketType; +import net.minecraft.util.Unit; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkStatus; +import org.apache.logging.log4j.Logger; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class PaperweightStarlightRelighter implements Relighter { + + public static final MethodHandle RELIGHT; + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 + private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting + + private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); + private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); + + static { + MethodHandle tmp = null; + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + tmp = lookup.findVirtual( + ThreadedLevelLightEngine.class, + "relight", + MethodType.methodType( + int.class, // return type + // params + Set.class, + Consumer.class, + IntConsumer.class + ) + ); + } catch (NoSuchMethodException | IllegalAccessException e) { + LOGGER.error("Failed to locate 'relight' method in ThreadedLevelLightEngine. Is everything up to date?", e); + } + RELIGHT = tmp; + } + + private final ServerLevel serverLevel; + private final ReentrantLock lock = new ReentrantLock(); + private final Long2ObjectLinkedOpenHashMap regions = new Long2ObjectLinkedOpenHashMap<>(); + private final ReentrantLock areaLock = new ReentrantLock(); + private final NMSRelighter delegate; + + public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { + this.serverLevel = serverLevel; + this.delegate = new NMSRelighter(queue); + } + + public static boolean isUsable() { + return RELIGHT != null; + } + + @Override + public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { + areaLock.lock(); + try { + long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2); + // TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH? + LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2)); + chunks.add(ChunkPos.asLong(cx, cz)); + } finally { + areaLock.unlock(); + } + return true; + } + + @Override + public void addLightUpdate(int x, int y, int z) { + delegate.addLightUpdate(x, y, z); + } + + /* + * This method is called "recursively", iterating and removing elements + * from the regions linked map. This way, chunks are loaded in batches to avoid + * OOMEs. + */ + @Override + public void fixLightingSafe(boolean sky) { + this.areaLock.lock(); + try { + if (regions.isEmpty()) { + return; + } + LongSet first = regions.removeFirst(); + fixLighting(first, () -> fixLightingSafe(true)); + } finally { + this.areaLock.unlock(); + } + } + + /* + * Processes a set of chunks and runs an action afterwards. + * The action is run async, the chunks are partly processed on the main thread + * (as required by the server). + */ + private void fixLighting(LongSet chunks, Runnable andThen) { + // convert from long keys to ChunkPos + Set coords = new HashSet<>(); + LongIterator iterator = chunks.iterator(); + while (iterator.hasNext()) { + coords.add(new ChunkPos(iterator.nextLong())); + } + TaskManager.taskManager().task(() -> { + // trigger chunk load and apply ticket on main thread + List> futures = new ArrayList<>(); + for (ChunkPos pos : coords) { + futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z) + .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( + FAWE_TICKET, + pos, + LIGHT_LEVEL, + Unit.INSTANCE + )) + ); + } + // collect futures and trigger relight once all chunks are loaded + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v -> + invokeRelight( + coords, + c -> { + }, // no callback for single chunks required + i -> { + if (i != coords.size()) { + LOGGER.warn("Processed {} chunks instead of {}", i, coords.size()); + } + // post process chunks on main thread + TaskManager.taskManager().task(() -> postProcessChunks(coords)); + // call callback on our own threads + TaskManager.taskManager().async(andThen); + } + ) + ); + }); + } + + private void invokeRelight( + Set coords, + Consumer chunkCallback, + IntConsumer processCallback + ) { + try { + int unused = (int) RELIGHT.invokeExact( + serverLevel.getChunkSource().getLightEngine(), + coords, + chunkCallback, // callback per chunk + processCallback // callback for all chunks + ); + } catch (Throwable throwable) { + LOGGER.error("Error occurred on relighting", throwable); + } + } + + /* + * Allow the server to unload the chunks again. + * Also, if chunk packets are sent delayed, we need to do that here + */ + private void postProcessChunks(Set coords) { + boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; + for (ChunkPos pos : coords) { + int x = pos.x; + int z = pos.z; + if (delay) { // we still need to send the block changes of that chunk + PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false); + } + serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); + } + } + + @Override + public void clear() { + + } + + @Override + public void removeLighting() { + this.delegate.removeLighting(); + } + + @Override + public void fixBlockLighting() { + fixLightingSafe(true); + } + + @Override + public void fixSkyLighting() { + fixLightingSafe(true); + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public ReentrantLock getLock() { + return this.lock; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public void close() throws Exception { + fixLightingSafe(true); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighterFactory.java new file mode 100644 index 000000000..a7da862fa --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightStarlightRelighterFactory.java @@ -0,0 +1,27 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; + +import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; +import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.fastasyncworldedit.core.queue.IQueueChunk; +import com.fastasyncworldedit.core.queue.IQueueExtent; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; + +import javax.annotation.Nonnull; + +public class PaperweightStarlightRelighterFactory implements RelighterFactory { + + @Override + public @Nonnull + Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { + org.bukkit.World w = Bukkit.getWorld(world.getName()); + if (w == null) { + return NullRelighter.INSTANCE; + } + return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/nbt/PaperweightLazyCompoundTag.java new file mode 100644 index 000000000..042c1f0e9 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/nbt/PaperweightLazyCompoundTag.java @@ -0,0 +1,158 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.LazyCompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import net.minecraft.nbt.NumericTag; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class PaperweightLazyCompoundTag extends LazyCompoundTag { + + private final Supplier compoundTagSupplier; + private CompoundTag compoundTag; + + public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { + super(new HashMap<>()); + this.compoundTagSupplier = compoundTagSupplier; + } + + public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { + this(() -> compoundTag); + } + + public net.minecraft.nbt.CompoundTag get() { + return compoundTagSupplier.get(); + } + + @Override + public Map getValue() { + if (compoundTag == null) { + compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); + } + return compoundTag.getValue(); + } + + @Override + public CompoundBinaryTag asBinaryTag() { + getValue(); + return compoundTag.asBinaryTag(); + } + + public boolean containsKey(String key) { + return compoundTagSupplier.get().contains(key); + } + + public byte[] getByteArray(String key) { + return compoundTagSupplier.get().getByteArray(key); + } + + public byte getByte(String key) { + return compoundTagSupplier.get().getByte(key); + } + + public double getDouble(String key) { + return compoundTagSupplier.get().getDouble(key); + } + + public double asDouble(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsDouble(); + } + return 0; + } + + public float getFloat(String key) { + return compoundTagSupplier.get().getFloat(key); + } + + public int[] getIntArray(String key) { + return compoundTagSupplier.get().getIntArray(key); + } + + public int getInt(String key) { + return compoundTagSupplier.get().getInt(key); + } + + public int asInt(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsInt(); + } + return 0; + } + + public List getList(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag nbtList) { + ArrayList list = new ArrayList<>(); + for (net.minecraft.nbt.Tag elem : nbtList) { + if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { + list.add(new PaperweightLazyCompoundTag(compoundTag)); + } else { + list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); + } + } + return list; + } + return Collections.emptyList(); + } + + public ListTag getListTag(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof net.minecraft.nbt.ListTag) { + return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); + } + return new ListTag(StringTag.class, Collections.emptyList()); + } + + @SuppressWarnings("unchecked") + public List getList(String key, Class listType) { + ListTag listTag = getListTag(key); + if (listTag.getType().equals(listType)) { + return (List) listTag.getValue(); + } else { + return Collections.emptyList(); + } + } + + public long[] getLongArray(String key) { + return compoundTagSupplier.get().getLongArray(key); + } + + public long getLong(String key) { + return compoundTagSupplier.get().getLong(key); + } + + public long asLong(String key) { + net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); + if (tag instanceof NumericTag numTag) { + return numTag.getAsLong(); + } + return 0; + } + + public short getShort(String key) { + return compoundTagSupplier.get().getShort(key); + } + + public String getString(String key) { + return compoundTagSupplier.get().getString(key); + } + + @Override + public String toString() { + return compoundTagSupplier.get().toString(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/regen/PaperweightRegen.java new file mode 100644 index 000000000..4269b48a5 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/regen/PaperweightRegen.java @@ -0,0 +1,497 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.regen; + +import com.fastasyncworldedit.bukkit.adapter.Regenerator; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.queue.IChunkCache; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.util.ReflectionUtils; +import com.fastasyncworldedit.core.util.TaskManager; +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1.PaperweightAdapter; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.PaperweightGetBlocks; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.file.SafeFiles; +import com.sk89q.worldedit.world.RegenOptions; +import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.blending.BlendingData; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_18_R1.CraftServer; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.generator.CustomChunkGenerator; +import org.bukkit.generator.BlockPopulator; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +public class PaperweightRegen extends Regenerator { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private static final Field serverWorldsField; + private static final Field paperConfigField; + private static final Field flatBedrockField; + private static final Field generatorSettingFlatField; + private static final Field generatorSettingBaseSupplierField; + private static final Field delegateField; + private static final Field chunkSourceField; + + //list of chunk stati in correct order without FULL + private static final Map chunkStati = new LinkedHashMap<>(); + + static { + chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing + chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps + chunkStati.put( + ChunkStatus.STRUCTURE_REFERENCES, + Concurrency.FULL + ); // structure refs: radius 8, but only writes to current chunk + chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 + chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 + chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE + chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results + chunkStati.put( + ChunkStatus.LIQUID_CARVERS, + Concurrency.NONE + ); // liquid carvers: radius 0, but RADIUS and FULL change results + chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps + chunkStati.put( + ChunkStatus.LIGHT, + Concurrency.FULL + ); // light: radius 1, but no writes to other chunks, only current chunk + chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 + chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 + + try { + serverWorldsField = CraftServer.class.getDeclaredField("worlds"); + serverWorldsField.setAccessible(true); + + Field tmpPaperConfigField; + Field tmpFlatBedrockField; + try { //only present on paper + tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); + tmpPaperConfigField.setAccessible(true); + + tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); + tmpFlatBedrockField.setAccessible(true); + } catch (Exception e) { + tmpPaperConfigField = null; + tmpFlatBedrockField = null; + } + paperConfigField = tmpPaperConfigField; + flatBedrockField = tmpFlatBedrockField; + + generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( + "settings", "f")); + generatorSettingBaseSupplierField.setAccessible(true); + + generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "e")); + generatorSettingFlatField.setAccessible(true); + + delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); + delegateField.setAccessible(true); + + chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L")); + chunkSourceField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + //runtime + private ServerLevel originalServerWorld; + private ServerChunkCache originalChunkProvider; + private ServerLevel freshWorld; + private ServerChunkCache freshChunkProvider; + private LevelStorageSource.LevelStorageAccess session; + private StructureManager structureManager; + private ThreadedLevelLightEngine threadedLevelLightEngine; + private ChunkGenerator chunkGenerator; + + private Path tempDir; + + private boolean generateFlatBedrock = false; + + public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { + super(originalBukkitWorld, region, target, options); + } + + @Override + protected boolean prepare() { + this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); + originalChunkProvider = originalServerWorld.getChunkSource(); + if (!(originalChunkProvider instanceof ServerChunkCache)) { + return false; + } + + //flat bedrock? (only on paper) + if (paperConfigField != null) { + try { + generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); + } catch (Exception ignored) { + } + } + + seed = options.getSeed().orElse(originalServerWorld.getSeed()); + chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c)); + + return true; + } + + @Override + protected boolean initNewWorld() throws Exception { + //world folder + tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); + + //prepare for world init (see upstream implementation for reference) + org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); + org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); + LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); + ResourceKey levelStemResourceKey = getWorldDimKey(environment); + session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); + PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; + + MinecraftServer server = originalServerWorld.getCraftServer().getServer(); + PrimaryLevelData levelProperties = (PrimaryLevelData) server.getWorldData(); + WorldGenSettings originalOpts = levelProperties.worldGenSettings(); + WorldGenSettings newOpts = options.getSeed().isPresent() + ? PaperweightAdapter.replaceSeed(originalServerWorld, seed, originalOpts) + : originalOpts; + LevelSettings newWorldSettings = new LevelSettings( + "faweregentempworld", + originalWorldData.settings.gameType(), + originalWorldData.settings.hardcore(), + originalWorldData.settings.difficulty(), + originalWorldData.settings.allowCommands(), + originalWorldData.settings.gameRules(), + originalWorldData.settings.getDataPackConfig() + ); + PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable()); + + //init world + freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( + server, + server.executor, + session, + newWorldData, + originalServerWorld.dimension(), + originalServerWorld.dimensionType(), + new RegenNoOpWorldLoadListener(), + // placeholder. Required for new ChunkProviderServer, but we create and then set it later + newOpts.dimensions().get(levelStemResourceKey).generator(), + originalServerWorld.isDebug(), + seed, + ImmutableList.of(), + false, + environment, + generator, + originalBukkitWorld.getBiomeProvider() + ) { + private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse( + options + .getBiomeType() + .getId())) : null; + + @Override + public void tick(BooleanSupplier shouldKeepTicking) { //no ticking + } + + @Override + public Biome getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + if (options.hasBiomeType()) { + return singleBiome; + } + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ, + PaperweightRegen.this.chunkGenerator.climateSampler() + ); + } + }).get(); + freshWorld.noSave = true; + removeWorldFromWorldsMap(); + newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name + if (paperConfigField != null) { + paperConfigField.set(freshWorld, originalServerWorld.paperConfig); + } + + //generator + if (originalChunkProvider.getGenerator() instanceof FlatLevelSource flatLevelSource) { + FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); + chunkGenerator = new FlatLevelSource(generatorSettingFlat); + } else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + Supplier generatorSettingBaseSupplier = (Supplier) generatorSettingBaseSupplierField + .get(originalChunkProvider.getGenerator()); + BiomeSource biomeSource = originalChunkProvider.getGenerator().getBiomeSource(); + chunkGenerator = new NoiseBasedChunkGenerator(noiseBasedChunkGenerator.noises, biomeSource, seed, + generatorSettingBaseSupplier + ); + } else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator customChunkGenerator) { + chunkGenerator = customChunkGenerator.delegate; + } else { + LOGGER.error("Unsupported generator type {}", originalChunkProvider.getGenerator().getClass().getName()); + return false; + } + if (generator != null) { + chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); + generateConcurrent = generator.isParallelCapable(); + } + + freshChunkProvider = new ServerChunkCache( + freshWorld, + session, + server.getFixerUpper(), + server.getStructureManager(), + server.executor, + chunkGenerator, + freshWorld.spigotConfig.viewDistance, + freshWorld.spigotConfig.simulationDistance, + server.forceSynchronousWrites(), + new RegenNoOpWorldLoadListener(), + (chunkCoordIntPair, state) -> { + }, + () -> server.overworld().getDataStorage() + ) { + // redirect to LevelChunks created in #createChunks + @Override + public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean flag) { + return getChunkAt(x, z); + } + }; + + ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); + //let's start then + structureManager = server.getStructureManager(); + threadedLevelLightEngine = freshChunkProvider.getLightEngine(); + + return true; + } + + @Override + protected void cleanup() { + try { + session.close(); + } catch (Exception ignored) { + } + + //shutdown chunk provider + try { + Fawe.instance().getQueueHandler().sync(() -> { + try { + freshChunkProvider.close(false); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } catch (Exception ignored) { + } + + //remove world from server + try { + Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); + } catch (Exception ignored) { + } + + //delete directory + try { + SafeFiles.tryHardToDeleteDir(tempDir); + } catch (Exception ignored) { + } + } + + @Override + protected ProtoChunk createProtoChunk(int x, int z) { + return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, + this.freshWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null + ); + } + + @Override + protected LevelChunk createChunk(ProtoChunk protoChunk) { + return new LevelChunk( + freshWorld, + protoChunk, + null // we don't want to add entities + ); + } + + @Override + protected ChunkStatusWrap getFullChunkStatus() { + return new ChunkStatusWrap(ChunkStatus.FULL); + } + + @Override + protected List getBlockPopulators() { + return originalServerWorld.getWorld().getPopulators(); + } + + @Override + protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { + // BlockPopulator#populate has to be called synchronously for TileEntity access + TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); + } + + @Override + protected IChunkCache initSourceQueueCache() { + return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { + @Override + public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { + return getChunkAt(x, z); + } + }; + } + + //util + private void removeWorldFromWorldsMap() { + Fawe.instance().getQueueHandler().sync(() -> { + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } + + private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { + return switch (env) { + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + default -> LevelStem.OVERWORLD; + }; + } + + private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { + + private RegenNoOpWorldLoadListener() { + } + + @Override + public void updateSpawnPos(ChunkPos spawnPos) { + } + + @Override + public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { + } + + @Override + public void start() { + + } + + @Override + public void stop() { + } + + // TODO Paper only(?) @Override + public void setChunkRadius(int radius) { + } + + } + + private class FastProtoChunk extends ProtoChunk { + + public FastProtoChunk( + final ChunkPos pos, + final UpgradeData upgradeData, + final LevelHeightAccessor world, + final Registry biomeRegistry, + @Nullable final BlendingData blendingData + ) { + super(pos, upgradeData, world, biomeRegistry, blendingData); + } + + // avoid warning on paper + + // compatibility with spigot + + public boolean generateFlatBedrock() { + return generateFlatBedrock; + } + + // no one will ever see the entities! + @Override + public List getEntities() { + return Collections.emptyList(); + } + + } + + protected class ChunkStatusWrap extends ChunkStatusWrapper { + + private final ChunkStatus chunkStatus; + + public ChunkStatusWrap(ChunkStatus chunkStatus) { + this.chunkStatus = chunkStatus; + } + + @Override + public int requiredNeighborChunkRadius() { + return chunkStatus.getRange(); + } + + @Override + public String name() { + return chunkStatus.getName(); + } + + @Override + public CompletableFuture processChunk(Long xz, List accessibleChunks) { + return chunkStatus.generate( + Runnable::run, // TODO revisit, we might profit from this somehow? + freshWorld, + chunkGenerator, + structureManager, + threadedLevelLightEngine, + c -> CompletableFuture.completedFuture(Either.left(c)), + accessibleChunks, + true + ); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/worldedit-adapters.jar index 6d4726c42..8171f289f 100644 Binary files a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/worldedit-adapters.jar and b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 447c05dad..fa1e999a7 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -42,12 +42,6 @@ repositories { flatDir { dir(File("src/main/resources")) } } -configurations.all { - resolutionStrategy { - force("com.google.guava:guava:21.0") - } -} - val localImplementation = configurations.create("localImplementation") { description = "Dependencies used locally, but provided by the runtime Bukkit implementation" isCanBeConsumed = false @@ -108,7 +102,6 @@ dependencies { compileOnly(libs.protocollib) { isTransitive = false } compileOnly(libs.plotsquaredV6Bukkit) { isTransitive = false } compileOnly(libs.plotsquaredV6Core) { isTransitive = false } - compileOnly(libs.plotsquaredV4) { isTransitive = false } // Third party compileOnly(libs.flowmath) { @@ -187,7 +180,7 @@ tasks.named("shadowJar") { include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.1")) } relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") { - include(dependency("com.intellectualsites.paster:Paster:1.1.1")) + include(dependency("com.intellectualsites.paster:Paster:1.1.3")) } relocate("org.lz4", "com.fastasyncworldedit.core.lz4") { include(dependency("org.lz4:lz4-java:1.8.0")) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java index 5e5671dcf..f207cd925 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java @@ -68,7 +68,6 @@ public class FaweBukkit implements IFawe, Listener { public FaweBukkit(Plugin plugin) { this.plugin = plugin; try { - Settings.IMP.TICK_LIMITER.ENABLED = !Bukkit.hasWhitelist(); Fawe.set(this); Fawe.setupInjector(); try { @@ -76,7 +75,7 @@ public class FaweBukkit implements IFawe, Listener { } catch (Throwable e) { LOGGER.error("Brush Listener Failed", e); } - if (PaperLib.isPaper() && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) { + if (PaperLib.isPaper() && Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) { new RenderListener(plugin); } } catch (final Throwable e) { @@ -84,17 +83,19 @@ public class FaweBukkit implements IFawe, Listener { Bukkit.getServer().shutdown(); } - chunksStretched = new MinecraftVersion().isEqualOrHigher(MinecraftVersion.NETHER); + MinecraftVersion version = new MinecraftVersion(); + + chunksStretched = version.isEqualOrHigherThan(MinecraftVersion.NETHER); platformAdapter = new NMSAdapter(); //PlotSquared support is limited to Spigot/Paper as of 02/20/2020 - TaskManager.IMP.later(this::setupPlotSquared, 0); + TaskManager.taskManager().later(this::setupPlotSquared, 0); // Registered delayed Event Listeners - TaskManager.IMP.task(() -> { + TaskManager.taskManager().task(() -> { // Fix for ProtocolSupport - Settings.IMP.PROTOCOL_SUPPORT_FIX = + Settings.settings().PROTOCOL_SUPPORT_FIX = Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport"); // This class @@ -103,6 +104,11 @@ public class FaweBukkit implements IFawe, Listener { // The tick limiter new ChunkListener9(); }); + + // Warn if small-edits are enabled with extended world heights + if (version.isEqualOrHigherThan(MinecraftVersion.CAVES_18) && Settings.settings().HISTORY.SMALL_EDITS) { + LOGGER.warn("Small-edits enabled (maximum y range of 0 -> 256) with 1.18 world heights. Are you sure?"); + } } @Override @@ -141,7 +147,7 @@ public class FaweBukkit implements IFawe, Listener { try { this.itemUtil = tmp = new ItemUtil(); } catch (Throwable e) { - Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES = false; + Settings.settings().EXPERIMENTAL.PERSISTENT_BRUSHES = false; LOGGER.error("Persistent Brushes Failed", e); } } @@ -310,14 +316,12 @@ public class FaweBukkit implements IFawe, Listener { if (plotSquared == null) { return; } - if (plotSquared.getClass().getPackage().toString().contains("intellectualsites")) { - WEManager.IMP.addManager(new com.fastasyncworldedit.bukkit.regions.plotsquaredv4.PlotSquaredFeature()); - LOGGER.info("Plugin 'PlotSquared' found. Using it now."); - } else if (PlotSquared.get().getVersion().version[0] == 6) { - WEManager.IMP.addManager(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature()); - LOGGER.info("Plugin 'PlotSquared' found. Using it now."); + if (PlotSquared.get().getVersion().version[0] == 6) { + WEManager.weManager().addManager(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature()); + LOGGER.info("Plugin 'PlotSquared' v6 found. Using it now."); } else { LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6."); + LOGGER.info("https://www.spigotmc.org/resources/77506/"); } } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java index aaac5c69f..29162b607 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java @@ -389,7 +389,7 @@ public interface IBukkitAdapter { * @return list of {@link org.bukkit.entity.Entity} */ default List getEntities(org.bukkit.World world) { - return TaskManager.IMP.sync(world::getEntities); + return TaskManager.taskManager().sync(world::getEntities); } } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java index f8d8cef2e..e0d13a36b 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java @@ -59,7 +59,7 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default BaseBlock getBlock(Location location) { + default BlockState getBlock(Location location) { return getParent().getBlock(location); } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java index 2f6dd6863..bb86a8bc4 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSAdapter.java @@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.world.block.BlockID; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; @@ -24,8 +23,8 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { int num_palette = 0; for (int i = 0; i < 4096; i++) { char ordinal = set[i]; - if (ordinal == BlockID.__RESERVED__) { - ordinal = BlockID.AIR; + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + ordinal = BlockTypesCache.ReservedIDs.AIR; } int palette = blockToPalette[ordinal]; if (palette == Integer.MAX_VALUE) { @@ -43,17 +42,15 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { } System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length); } - char lastOrdinal = BlockID.__RESERVED__; + char lastOrdinal = 0; boolean lastticking = false; - boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED; + boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED; for (int i = 0; i < 4096; i++) { char ordinal = set[i]; switch (ordinal) { - case BlockID.__RESERVED__: - ordinal = BlockID.AIR; - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: + case BlockTypesCache.ReservedIDs.__RESERVED__: + ordinal = BlockTypesCache.ReservedIDs.AIR; + case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR: air++; break; default: @@ -95,13 +92,13 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { char[] getArr = null; for (int i = 0; i < 4096; i++) { char ordinal = set[i]; - if (ordinal == BlockID.__RESERVED__) { + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { if (getArr == null) { getArr = get.apply(layer); } ordinal = getArr[i]; - if (ordinal == BlockID.__RESERVED__) { - ordinal = BlockID.AIR; + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + ordinal = BlockTypesCache.ReservedIDs.AIR; } } int palette = blockToPalette[ordinal]; @@ -120,26 +117,23 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { } System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length); } - char lastOrdinal = BlockID.__RESERVED__; + char lastOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; boolean lastticking = false; - boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED; - boolean tick_existing = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_EXISTING; + boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED; + boolean tick_existing = Settings.settings().EXPERIMENTAL.ALLOW_TICK_EXISTING; for (int i = 0; i < 4096; i++) { char ordinal = set[i]; switch (ordinal) { - case BlockID.__RESERVED__: { + case BlockTypesCache.ReservedIDs.__RESERVED__ -> { if (getArr == null) { getArr = get.apply(layer); } - ordinal = getArr[i]; - switch (ordinal) { - case BlockID.__RESERVED__: - ordinal = BlockID.AIR; - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: + set[i] = switch (ordinal = getArr[i]) { + case BlockTypesCache.ReservedIDs.__RESERVED__: + ordinal = BlockTypesCache.ReservedIDs.AIR; + case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR: air++; - break; + yield ordinal; default: if (!fastmode && !tick_placed && tick_existing) { boolean ticking; @@ -152,23 +146,19 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl { } if (ticking) { BlockState state = BlockState.getFromOrdinal(ordinal); - ticking_blocks - .put( - BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15), - WorldEditPlugin.getInstance().getBukkitImplAdapter() - .getInternalBlockStateId(state).orElse(0) - ); + ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15), + WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBlockStateId(state) + .orElse(0) + ); } } - } - set[i] = ordinal; - break; + yield ordinal; + }; } - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - air++; - break; + case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> air++; } if (!fastmode && tick_placed) { boolean ticking; diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java index 89f16bafd..4fd78df85 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/NMSRelighterFactory.java @@ -18,7 +18,7 @@ public class NMSRelighterFactory implements RelighterFactory { Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { return new NMSRelighter( queue, - relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE) + relightMode != null ? relightMode : RelightMode.valueOf(Settings.settings().LIGHTING.MODE) ); } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java index 97e15b9a6..576e88aab 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/Regenerator.java @@ -5,7 +5,10 @@ import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent; import com.fastasyncworldedit.core.util.MathMan; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; @@ -32,6 +35,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -151,7 +155,10 @@ public abstract class Regenerator biome)); + } else if (genbiomes) { + target.setBlocks(region, new WithBiomePlacementPattern(vec -> source.getBiome(vec))); + } + } + + private class PlacementPattern implements Pattern { + + @Override + public BaseBlock applyBlock(final BlockVector3 position) { + return source.getFullBlock(position); + } + + @Override + public boolean apply(final Extent extent, final BlockVector3 get, final BlockVector3 set) throws WorldEditException { + return extent.setBlock(set.getX(), set.getY(), set.getZ(), source.getFullBlock(get.getX(), get.getY(), get.getZ())); + } + + } + + private class WithBiomePlacementPattern implements Pattern { + + private final Function biomeGetter; + + private WithBiomePlacementPattern(final Function biomeGetter) { + this.biomeGetter = biomeGetter; + } + + @Override + public BaseBlock applyBlock(final BlockVector3 position) { + return source.getFullBlock(position); + } + + @Override + public boolean apply(final Extent extent, final BlockVector3 get, final BlockVector3 set) throws WorldEditException { + return extent.setBlock(set.getX(), set.getY(), set.getZ(), source.getFullBlock(get.getX(), get.getY(), get.getZ())) + && extent.setBiome(set.getX(), set.getY(), set.getZ(), biomeGetter.apply(get)); + } + } //functions to be implemented by sub class diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java index 69ba73344..5d2e35335 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener.java @@ -45,20 +45,25 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.util.Vector; +/** + * @deprecated FAWE is not necessarily the tool you want to use to limit certain tick actions, e.g. fireworks or elytra flying. + * The code is untouched since the 1.12 era and there is no guarantee that it will work or will be maintained in the future. + */ +@Deprecated(since = "2.0.0") public abstract class ChunkListener implements Listener { private static final Logger LOGGER = LogManagerCompat.getLogger(); protected int rateLimit = 0; protected Location lastCancelPos; - private final int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS, - Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS}; + private final int[] badLimit = new int[]{Settings.settings().TICK_LIMITER.PHYSICS_MS, + Settings.settings().TICK_LIMITER.FALLING, Settings.settings().TICK_LIMITER.ITEMS}; public ChunkListener() { - if (Settings.IMP.TICK_LIMITER.ENABLED) { + if (Settings.settings().TICK_LIMITER.ENABLED) { PluginManager plm = Bukkit.getPluginManager(); - Plugin plugin = Fawe.imp().getPlugin(); + Plugin plugin = Fawe.platform().getPlugin(); plm.registerEvents(this, plugin); - TaskManager.IMP.repeat(() -> { + TaskManager.taskManager().repeat(() -> { Location tmpLoc = lastCancelPos; if (tmpLoc != null) { LOGGER.info("[FAWE Tick Limiter] Detected and cancelled physics lag source at {}", tmpLoc); @@ -80,7 +85,7 @@ public abstract class ChunkListener implements Listener { counter.put(key, badLimit); } badChunks.clear(); - }, Settings.IMP.TICK_LIMITER.INTERVAL); + }, Settings.settings().TICK_LIMITER.INTERVAL); } } @@ -88,7 +93,15 @@ public abstract class ChunkListener implements Listener { protected abstract StackTraceElement getElement(Exception ex, int index); + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public static boolean physicsFreeze = false; + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public static boolean itemFreeze = false; protected final Long2ObjectOpenHashMap badChunks = new Long2ObjectOpenHashMap<>(); @@ -97,6 +110,10 @@ public abstract class ChunkListener implements Listener { private int lastZ = Integer.MIN_VALUE; private int[] lastCount; + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public int[] getCount(int cx, int cz) { if (lastX == cx && lastZ == cz) { return lastCount; @@ -112,6 +129,10 @@ public abstract class ChunkListener implements Listener { return tmp; } + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public void cleanup(Chunk chunk) { for (Entity entity : chunk.getEntities()) { if (entity.getType() == EntityType.DROPPED_ITEM) { @@ -128,6 +149,10 @@ public abstract class ChunkListener implements Listener { protected long physStart; protected long physTick; + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public final void reset() { physSkip = 0; physStart = System.currentTimeMillis(); @@ -241,13 +266,13 @@ public abstract class ChunkListener implements Listener { if ((++physSkip & 1023) != 0) { return; } - FaweTimer timer = Fawe.get().getTimer(); + FaweTimer timer = Fawe.instance().getTimer(); if (timer.getTick() != physTick) { physTick = timer.getTick(); physStart = System.currentTimeMillis(); return; } else if (System.currentTimeMillis() - physStart - < Settings.IMP.TICK_LIMITER.PHYSICS_MS) { + < Settings.settings().TICK_LIMITER.PHYSICS_MS) { return; } } @@ -324,15 +349,15 @@ public abstract class ChunkListener implements Listener { int cx = x >> 4; int cz = z >> 4; int[] count = getCount(cx, cz); - if (count[1] >= Settings.IMP.TICK_LIMITER.FALLING) { + if (count[1] >= Settings.settings().TICK_LIMITER.FALLING) { event.setCancelled(true); return; } if (event.getEntityType() == EntityType.FALLING_BLOCK) { - if (++count[1] >= Settings.IMP.TICK_LIMITER.FALLING) { + if (++count[1] >= Settings.settings().TICK_LIMITER.FALLING) { // Only cancel falling blocks when it's lagging - if (Fawe.get().getTimer().getTPS() < 18) { + if (Fawe.instance().getTimer().getTPS() < 18) { cancelNearby(cx, cz); if (rateLimit <= 0) { rateLimit = 20; @@ -351,7 +376,7 @@ public abstract class ChunkListener implements Listener { */ @EventHandler(priority = EventPriority.LOWEST) public void onChunkLoad(ChunkLoadEvent event) { - if (!Settings.IMP.TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) { + if (!Settings.settings().TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) { Chunk chunk = event.getChunk(); Entity[] entities = chunk.getEntities(); World world = chunk.getWorld(); @@ -377,8 +402,8 @@ public abstract class ChunkListener implements Listener { if (Math.abs(velocity.getX()) > vertical || Math.abs(velocity.getZ()) > vertical) { LOGGER.warn( - "[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at " - + ent.getLocation()); + "[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at {}", + ent.getLocation()); ent.remove(); } } @@ -398,17 +423,17 @@ public abstract class ChunkListener implements Listener { int cx = loc.getBlockX() >> 4; int cz = loc.getBlockZ() >> 4; int[] count = getCount(cx, cz); - if (count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) { + if (count[2] >= Settings.settings().TICK_LIMITER.ITEMS) { event.setCancelled(true); return; } - if (++count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) { + if (++count[2] >= Settings.settings().TICK_LIMITER.ITEMS) { cleanup(loc.getChunk()); cancelNearby(cx, cz); if (rateLimit <= 0) { rateLimit = 20; LOGGER.warn( - "[FAWE `tick-limiter`] Detected and cancelled item lag source at " + loc); + "[FAWE `tick-limiter`] Detected and cancelled item lag source at {}", loc); } event.setCancelled(true); } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener9.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener9.java index 0726af748..c20435ac3 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener9.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/ChunkListener9.java @@ -9,11 +9,20 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPhysicsEvent; +/** + * @deprecated FAWE is not necessarily the tool you want to use to limit certain tick actions, e.g. fireworks or elytra flying. + * The code is untouched since the 1.12 era and there is no guarantee that it will work or will be maintained in the future. + */ +@Deprecated(since = "2.0.0") public class ChunkListener9 extends ChunkListener { private Exception exception; private StackTraceElement[] elements; + /** + * @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener9} for an explanation of the deprecation + */ + @Deprecated(since = "2.0.0") public ChunkListener9() { super(); } @@ -37,13 +46,13 @@ public class ChunkListener9 extends ChunkListener { event.setCancelled(true); return; } - if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) { + if (System.currentTimeMillis() - physStart > Settings.settings().TICK_LIMITER.PHYSICS_MS) { physCancelPair = pair; event.setCancelled(true); return; } } - FaweTimer timer = Fawe.get().getTimer(); + FaweTimer timer = Fawe.instance().getTimer(); if (timer.getTick() != physTick) { physTick = timer.getTick(); physStart = System.currentTimeMillis(); @@ -52,7 +61,7 @@ public class ChunkListener9 extends ChunkListener { return; } if ((++physSkip & 1023) == 0) { - if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) { + if (System.currentTimeMillis() - physStart > Settings.settings().TICK_LIMITER.PHYSICS_MS) { Block block = event.getBlock(); int cx = block.getX() >> 4; int cz = block.getZ() >> 4; diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/RenderListener.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/RenderListener.java index c76d85739..22a09deb8 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/RenderListener.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/listener/RenderListener.java @@ -28,7 +28,7 @@ public class RenderListener implements Listener { public RenderListener(Plugin plugin) { Bukkit.getPluginManager().registerEvents(this, plugin); - TaskManager.IMP.repeat(new Runnable() { + TaskManager.taskManager().repeat(new Runnable() { private long last = 0; @Override @@ -38,7 +38,7 @@ public class RenderListener implements Listener { } long now = System.currentTimeMillis(); - int tps32 = (int) (Math.round(Fawe.get().getTimer().getTPS()) * 32); + int tps32 = (int) (Math.round(Fawe.instance().getTimer().getTPS()) * 32); long diff = now - last; last = now; if (diff > 75) { @@ -56,7 +56,7 @@ public class RenderListener implements Listener { if (entrySet == null || !entrySet.hasNext()) { entrySet = views.entrySet().iterator(); } - int nowTick = (int) (Fawe.get().getTimer().getTick()); + int nowTick = (int) (Fawe.instance().getTimer().getTick()); while (entrySet.hasNext()) { Map.Entry entry = entrySet.next(); Player player = Bukkit.getPlayer(entry.getKey()); @@ -81,17 +81,17 @@ public class RenderListener implements Listener { private void setViewDistance(Player player, int value) { UUID uuid = player.getUniqueId(); - if (value == Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) { + if (value == Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) { views.remove(uuid); } else { int[] val = views.get(uuid); if (val == null) { - val = new int[]{value, (int) Fawe.get().getTimer().getTick()}; + val = new int[]{value, (int) Fawe.instance().getTimer().getTick()}; UUID uid = player.getUniqueId(); views.put(uid, val); } else { if (value <= val[0]) { - val[1] = (int) Fawe.get().getTimer().getTick(); + val[1] = (int) Fawe.instance().getTimer().getTick(); } if (val[0] == value) { return; @@ -105,7 +105,7 @@ public class RenderListener implements Listener { private int getViewDistance(Player player) { int[] value = views.get(player.getUniqueId()); - return value == null ? Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING : value[0]; + return value == null ? Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING : value[0]; } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java index 3a09a9aa8..1f9fc7233 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java @@ -32,7 +32,7 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener } @Override - public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) { + public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) { final Player player = BukkitAdapter.adapt(wePlayer); final Location loc = player.getLocation(); final Vector3i vector = Vector3i.from(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java index a54f3a0af..c75349b76 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java @@ -1,7 +1,9 @@ package com.fastasyncworldedit.bukkit.regions; import com.fastasyncworldedit.core.regions.FaweMask; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; @@ -30,7 +32,7 @@ public class GriefPreventionFeature extends BukkitMaskManager implements Listene } @Override - public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) { + public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) { final Player player = BukkitAdapter.adapt(wePlayer); final Claim claim = GriefPrevention.instance.dataStore.getClaimAt(player.getLocation(), true, null); if (claim != null) { @@ -38,12 +40,12 @@ public class GriefPreventionFeature extends BukkitMaskManager implements Listene claim.getGreaterBoundaryCorner().getBlockX(); final BlockVector3 pos1 = BlockVector3.at( claim.getLesserBoundaryCorner().getBlockX(), - 0, + player.getWorld().getMinHeight(), claim.getLesserBoundaryCorner().getBlockZ() ); final BlockVector3 pos2 = BlockVector3.at( claim.getGreaterBoundaryCorner().getBlockX(), - 256, + player.getWorld().getMaxHeight(), claim.getGreaterBoundaryCorner().getBlockZ() ); return new FaweMask(new CuboidRegion(pos1, pos2)) { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/ResidenceFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/ResidenceFeature.java index c6b75f8c6..d72769176 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/ResidenceFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/ResidenceFeature.java @@ -33,13 +33,13 @@ public class ResidenceFeature extends BukkitMaskManager implements Listener { return residence != null && (residence.getOwner().equals(player.getName()) || residence.getOwner().equals(player.getUniqueId().toString()) || - type == MaskType.MEMBER && TaskManager.IMP.sync(() -> residence + type == MaskType.MEMBER && TaskManager.taskManager().sync(() -> residence .getPermissions() .playerHas(player, "build", false))); } @Override - public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, final MaskType type) { + public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, final MaskType type, boolean isWhitelist) { final Player player = BukkitAdapter.adapt(wePlayer); final Location location = player.getLocation(); ClaimedResidence residence = Residence.getInstance().getResidenceManager().getByLoc(location); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/TownyFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/TownyFeature.java index 231ee9ea3..c46c4c0a3 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/TownyFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/TownyFeature.java @@ -66,7 +66,7 @@ public class TownyFeature extends BukkitMaskManager implements Listener { } @Override - public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) { + public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) { final Player player = BukkitAdapter.adapt(wePlayer); final Location location = player.getLocation(); try { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java index 7d10ac33a..d50300106 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateRegionManager.java @@ -53,7 +53,7 @@ public class FaweDelegateRegionManager { int maxY, Runnable whenDone ) { - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { World world = BukkitAdapter.adapt(getWorld(area.getWorldName())); EditSession session = WorldEdit.getInstance().newEditSessionBuilder().world(world).checkMemory(false). @@ -67,14 +67,14 @@ public class FaweDelegateRegionManager { session.flushQueue(); for (CuboidRegion region : regions) { FaweAPI.fixLighting(world, region, null, - RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE) + RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); } } catch (MaxChangedBlocksException e) { e.printStackTrace(); } finally { if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } } } @@ -92,7 +92,7 @@ public class FaweDelegateRegionManager { @Nullable Runnable whenDone, @Nonnull PlotManager manager ) { - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { final HybridPlotWorld hybridPlotWorld = ((HybridPlotManager) manager).getHybridPlotWorld(); World world = BukkitAdapter.adapt(getWorld(hybridPlotWorld.getWorldName())); @@ -176,10 +176,10 @@ public class FaweDelegateRegionManager { world, new CuboidRegion(plot.getBottomAbs().getBlockVector3(), plot.getTopAbs().getBlockVector3()), null, - RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE) + RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } } }); @@ -192,7 +192,7 @@ public class FaweDelegateRegionManager { Location swapPos, final Runnable whenDone ) { - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { //todo because of the following code this should proably be in the Bukkit module World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName())); @@ -220,18 +220,22 @@ public class FaweDelegateRegionManager { Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID()); ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, clipA, clipA.getMinimumPoint()); ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, clipB, clipB.getMinimumPoint()); + copyA.setCopyingBiomes(true); + copyB.setCopyingBiomes(true); try { Operations.completeLegacy(copyA); Operations.completeLegacy(copyB); - clipA.paste(sessionB, swapPos.getBlockVector3(), true); - clipB.paste(sessionA, pos1.getBlockVector3(), true); - sessionA.flushQueue(); - sessionB.flushQueue(); + clipA.flush(); + clipB.flush(); + clipA.paste(sessionB, swapPos.getBlockVector3(), true, true, true); + clipB.paste(sessionA, pos1.getBlockVector3(), true, true, true); + sessionA.close(); + sessionB.close(); } catch (MaxChangedBlocksException e) { e.printStackTrace(); } FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null, - RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE) + RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); FaweAPI.fixLighting(pos1World, new CuboidRegion( swapPos.getBlockVector3(), @@ -241,10 +245,10 @@ public class FaweDelegateRegionManager { swapPos.getZ() + pos2.getZ() - pos1.getZ() ) ), null, - RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE) + RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } } }); @@ -253,7 +257,7 @@ public class FaweDelegateRegionManager { public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, String world, Runnable whenDone) { region.expand(BlockVector3.at(extendBiome, 0, extendBiome)); region.expand(BlockVector3.at(-extendBiome, 0, -extendBiome)); - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { EditSession editSession = WorldEdit .getInstance() @@ -273,7 +277,7 @@ public class FaweDelegateRegionManager { e.printStackTrace(); } if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } } }); @@ -285,7 +289,7 @@ public class FaweDelegateRegionManager { final @NonNull Location pos3, final @NonNull Runnable whenDone ) { - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName())); World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorldName())); @@ -319,21 +323,21 @@ public class FaweDelegateRegionManager { pos3.getBlockVector3(), pos3.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3())) ), - null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE) + null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); } catch (MaxChangedBlocksException e) { e.printStackTrace(); } } if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } }); return true; } public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) { - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName())); try (EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World) @@ -350,7 +354,7 @@ public class FaweDelegateRegionManager { editSession.flushQueue(); } if (whenDone != null) { - TaskManager.IMP.task(whenDone); + TaskManager.taskManager().task(whenDone); } } }); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java index e61cacce2..2195980c8 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java @@ -132,7 +132,7 @@ public class FaweDelegateSchematicHandler { } }; if (Fawe.isMainThread()) { - com.fastasyncworldedit.core.util.TaskManager.IMP.async(r); + com.fastasyncworldedit.core.util.TaskManager.taskManager().async(r); } else { r.run(); } @@ -186,7 +186,7 @@ public class FaweDelegateSchematicHandler { } return; } - final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag); + final CompoundTag weTag = (CompoundTag) FaweCache.INSTANCE.asTag(tag); SchematicHandler.upload(uuid, file, "schem", new RunnableVal<>() { @Override public void run(OutputStream output) { @@ -235,10 +235,8 @@ public class FaweDelegateSchematicHandler { Clipboard clip = schematicReader.read(); return new Schematic(clip); } catch (IOException e3) { + LOGGER.warn("{} | {} : {}", is, is.getClass().getCanonicalName(), e.getMessage()); e.printStackTrace(); - LOGGER.warn( - is + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e - .getMessage()); } } } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweQueueCoordinator.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweQueueCoordinator.java index 692a594aa..9c8888a8e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweQueueCoordinator.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweQueueCoordinator.java @@ -35,8 +35,8 @@ public class FaweQueueCoordinator extends QueueCoordinator { public FaweQueueCoordinator(World world) { super(world); this.world = world; - instance = Fawe.get().getQueueHandler().getQueue(world); - Fawe.get().getQueueHandler().unCache(); + instance = Fawe.instance().getQueueHandler().getQueue(world); + Fawe.instance().getQueueHandler().unCache(); } @Override @@ -194,7 +194,7 @@ public class FaweQueueCoordinator extends QueueCoordinator { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag)); + instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.INSTANCE.asTag(tag)); return true; } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweTrim.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweTrim.java index f2621d90b..8bfab4939 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweTrim.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweTrim.java @@ -37,7 +37,7 @@ public class FaweTrim extends SubCommand { return false; } ran = true; - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { try { // TODO NOT IMPLEMENTED //PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1])); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSetBiome.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSetBiome.java index 3977cf808..87db6655a 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSetBiome.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSetBiome.java @@ -89,7 +89,7 @@ public class PlotSetBiome extends Command { return; } plot.addRunning(); - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { EditSession session = WorldEdit .getInstance() diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java index 5dfc76ee9..d900c6c24 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java @@ -4,9 +4,6 @@ import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.regions.FaweMask; import com.fastasyncworldedit.core.regions.FaweMaskManager; -import com.fastasyncworldedit.core.regions.filter.RegionFilter; -import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.player.PlotPlayer; @@ -62,6 +59,15 @@ public class PlotSquaredFeature extends FaweMaskManager { */ } + /** + * Whether the player is allowed to use FAWE on a PlotSquared plot. + * + * @param player the {@link Player} + * @param plot the {@link Plot} + * @param type the {@link MaskType} + * @return {@code true} if the player is the plot owner, trusted, has the permission fawe.plotsquared.member + * or fawe.plotsquared.admin and the NoWorldeditFlag is not set; otherwise {@code false} + */ public boolean isAllowed(Player player, Plot plot, MaskType type) { if (plot == null) { return false; @@ -121,7 +127,7 @@ public class PlotSquaredFeature extends FaweMaskManager { } @Override - public FaweMask getMask(Player player, MaskType type) { + public FaweMask getMask(Player player, MaskType type, boolean isWhitelist) { final PlotPlayer pp = PlotPlayer.from(BukkitAdapter.adapt(player)); if (pp == null) { return null; diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/ReplaceAll.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/ReplaceAll.java index d894596df..ed77b3668 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/ReplaceAll.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/ReplaceAll.java @@ -46,9 +46,9 @@ public class ReplaceAll extends Command { plot.addRunning(); FawePlayer fp = FawePlayer.wrap(player.getName()); Captions.TASK_START.send(player); - TaskManager.IMP.async(() -> fp.runAction(() -> { + TaskManager.taskManager().async(() -> fp.runAction(() -> { String worldName = plot.getWorldName(); - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Object value) { SetupUtils.manager.unload(worldName, true); @@ -58,7 +58,7 @@ public class ReplaceAll extends Command { String cmd = "/replaceallpattern " + worldName + " " + StringMan.join(args, " "); CommandEvent event = new CommandEvent(actor, cmd); PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event); - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Object value) { plot.teleportPlayer(player); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweChunkManager.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweChunkManager.java deleted file mode 100644 index 4f50f63ac..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweChunkManager.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.util.TaskManager; -import com.github.intellectualsites.plotsquared.plot.object.Location; -import com.github.intellectualsites.plotsquared.plot.object.Plot; -import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.function.operation.ForwardExtentCopy; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.World; - -import java.util.concurrent.CompletableFuture; - -import static org.bukkit.Bukkit.getWorld; - -public class FaweChunkManager extends ChunkManager { - - private final ChunkManager parent; - - public FaweChunkManager(ChunkManager parent) { - this.parent = parent; - } - - @Override - public int[] countEntities(Plot plot) { - return parent.countEntities(plot); - } - - @Override - public CompletableFuture loadChunk(String world, BlockVector2 loc, boolean force) { - return parent.loadChunk(world, loc, force); - } - - @Override - public void unloadChunk(String world, BlockVector2 loc, boolean save) { - parent.unloadChunk(world, loc, save); - } - - @Override - public void clearAllEntities(Location pos1, Location pos2) { - parent.clearAllEntities(pos1, pos2); - } - - @Override - public void swap( - final Location pos1, - final Location pos2, - final Location pos3, - final Location pos4, - final Runnable whenDone - ) { - if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) { - parent.swap(pos1, pos2, pos3, pos4, whenDone); - } - TaskManager.IMP.async(() -> { - synchronized (FaweChunkManager.class) { - //todo because of the following code this should proably be in the Bukkit module - World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld())); - World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld())); - EditSession sessionA = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build(); - EditSession sessionB = WorldEdit.getInstance().newEditSessionBuilder().world(pos3World) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build(); - CuboidRegion regionA = new CuboidRegion( - BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), - BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()) - ); - CuboidRegion regionB = new CuboidRegion( - BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()), - BlockVector3.at(pos4.getX(), pos4.getY(), pos4.getZ()) - ); - ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint()); - ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint()); - try { - Operations.completeLegacy(copyA); - Operations.completeLegacy(copyB); - sessionA.flushQueue(); - sessionB.flushQueue(); - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - } - TaskManager.IMP.task(whenDone); - } - }); - } - - @Override - public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) { - if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) { - return parent.copyRegion(pos1, pos2, pos3, whenDone); - } - TaskManager.IMP.async(() -> { - synchronized (FaweChunkManager.class) { - World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld())); - World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld())); - EditSession from = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build(); - EditSession to = WorldEdit.getInstance().newEditSessionBuilder().world(pos3World) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build(); - CuboidRegion region = new CuboidRegion( - BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), - BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()) - ); - ForwardExtentCopy copy = new ForwardExtentCopy( - from, - region, - to, - BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()) - ); - try { - Operations.completeLegacy(copy); - to.flushQueue(); - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - } - } - TaskManager.IMP.task(whenDone); - }); - return true; - } - - @Override - public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) { - TaskManager.IMP.async(() -> { - synchronized (FaweChunkManager.class) { - World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld())); - try (EditSession editSession = WorldEdit - .getInstance() - .newEditSessionBuilder() - .world(pos1World) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build()) { - CuboidRegion region = new CuboidRegion( - BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), - BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()) - ); - editSession.regenerate(region); - editSession.flushQueue(); - } - TaskManager.IMP.task(whenDone); - } - }); - return true; - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweLocalBlockQueue.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweLocalBlockQueue.java deleted file mode 100644 index fb27c01ed..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweLocalBlockQueue.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweAPI; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -// TODO FIXME -public class FaweLocalBlockQueue extends LocalBlockQueue { - - public final IQueueExtent instance; - private final World world; - private final BlockVector3 mutable = new MutableBlockVector3(); - - public FaweLocalBlockQueue(String worldName) { - super(worldName); - this.world = FaweAPI.getWorld(worldName); - instance = Fawe.get().getQueueHandler().getQueue(world); - Fawe.get().getQueueHandler().unCache(); - } - - @Override - public boolean next() { - if (!instance.isEmpty()) { - instance.flush(); - } - return false; - } - - @Override - public void startSet(boolean parallel) { - Fawe.get().getQueueHandler().startSet(parallel); - } - - @Override - public void endSet(boolean parallel) { - Fawe.get().getQueueHandler().endSet(parallel); - } - - @Override - public int size() { - return instance.isEmpty() ? 0 : 1; - } - - @Override - public void optimize() { - } - - @Override - public void setModified(long l) { - } - - @Override - public long getModified() { - return instance.size(); - } - - @Override - public boolean setBlock(final int x, final int y, final int z, final BlockState id) { - return instance.setBlock(x, y, z, id); - } - - @Override - public boolean setBlock(int x, int y, int z, Pattern pattern) { - mutable.setComponents(x, y, z); - return pattern.apply(instance, mutable, mutable); - } - - @Override - public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) { - return instance.setBlock(x, y, z, id); - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return instance.getBlock(x, y, z); - } - - @Override - public boolean setBiome(int x, int z, BiomeType biomeType) { - return instance.setBiome(x, 0, z, biomeType); - } - - @Override - public String getWorld() { - return world.getId(); - } - - @Override - public void flush() { - instance.flush(); - } - - @Override - public boolean enqueue() { - boolean val = super.enqueue(); - instance.enableQueue(); - return val; - } - - @Override - public void refreshChunk(int x, int z) { - world.refreshChunk(x, z); - } - - @Override - public void fixChunkLighting(int x, int z) { - } - - @Override - public void regenChunk(int x, int z) { - instance.regenerateChunk(x, z, null, null); - } - - @Override - public boolean setTile(int x, int y, int z, CompoundTag tag) { - instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag)); - return true; - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java deleted file mode 100644 index 06921cb12..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.FaweAPI; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; -import com.fastasyncworldedit.core.jnbt.CompressedCompoundTag; -import com.fastasyncworldedit.core.jnbt.CompressedSchematicTag; -import com.fastasyncworldedit.core.util.IOUtil; -import com.fastasyncworldedit.core.util.TaskManager; -import com.github.intellectualsites.plotsquared.plot.PlotSquared; -import com.github.intellectualsites.plotsquared.plot.object.Location; -import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; -import com.github.intellectualsites.plotsquared.plot.util.MainUtil; -import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; -import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.World; -import net.jpountz.lz4.LZ4BlockInputStream; -import org.anarres.parallelgzip.ParallelGZIPOutputStream; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URL; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import static org.bukkit.Bukkit.getWorld; - -public class FaweSchematicHandler extends SchematicHandler { - - @Override - public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) { - if (queue instanceof FaweLocalBlockQueue) { - queue.setTile(x, y, z, compoundTag); - return true; - } - return false; - } - - @Override - public void getCompoundTag(final String world, final Set regions, final RunnableVal whenDone) { - TaskManager.IMP.async(() -> { - Location[] corners = MainUtil.getCorners(world, regions); - Location pos1 = corners[0]; - Location pos2 = corners[1]; - World adaptedWorld = BukkitAdapter.adapt(getWorld(world)); - final CuboidRegion region = new CuboidRegion( - BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), - BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()) - ); - final EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(adaptedWorld) - .checkMemory(false) - .fastMode(true) - .limitUnlimited() - .changeSetNull() - .build(); - - ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true); - - Clipboard holder = new BlockArrayClipboard(region, clipboard); - - CompressedSchematicTag tag = new CompressedSchematicTag(holder); - whenDone.run(tag); - }); - } - - @Override - public boolean save(CompoundTag tag, String path) { - if (tag == null) { - PlotSquared.debug("&cCannot save empty tag"); - return false; - } - try { - File tmp = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), path); - tmp.getParentFile().mkdirs(); - if (tag instanceof CompressedCompoundTag) { - CompressedCompoundTag cTag = (CompressedCompoundTag) tag; - if (cTag instanceof CompressedSchematicTag) { - Clipboard clipboard = (Clipboard) cTag.getSource(); - try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream( - new ParallelGZIPOutputStream(stream)))) { - new FastSchematicWriter(output).write(clipboard); - } - } else { - try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream( - new ParallelGZIPOutputStream(stream))) { - LZ4BlockInputStream is = cTag.adapt(cTag.getSource()); - IOUtil.copy(is, stream); - } - } - } else { - try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new ParallelGZIPOutputStream( - stream))) { - Map map = tag.getValue(); - output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag)); - } - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - return true; - } - - @Override - public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal whenDone) { - if (tag == null) { - PlotSquared.debug("&cCannot save empty tag"); - com.github.intellectualsites.plotsquared.plot.util.TaskManager.runTask(whenDone); - return; - } - CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag); - if (weTag instanceof CompressedSchematicTag) { - Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource(); - URL url = FaweAPI.upload(clipboard, BuiltInClipboardFormat.SPONGE_SCHEMATIC); - whenDone.run(url); - return; - } - MainUtil.upload(uuid, file, "schem", new RunnableVal() { - @Override - public void run(OutputStream output) { - try { - try (ParallelGZIPOutputStream gzip = new ParallelGZIPOutputStream(output)) { - try (NBTOutputStream nos = new NBTOutputStream(gzip)) { - Map map = weTag.getValue(); - nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag)); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - }, whenDone); - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweTrim.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweTrim.java deleted file mode 100644 index 0c5f02b59..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/FaweTrim.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.util.TaskManager; -import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; -import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory; -import com.github.intellectualsites.plotsquared.plot.commands.RequiredType; -import com.github.intellectualsites.plotsquared.plot.commands.SubCommand; -import com.github.intellectualsites.plotsquared.plot.config.Captions; -import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; -import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; - -@CommandDeclaration( - command = "trimchunks", - permission = "plots.admin", - description = "Delete unmodified portions of your plotworld", - requiredType = RequiredType.PLAYER, - category = CommandCategory.ADMINISTRATION) -public class FaweTrim extends SubCommand { - - private boolean ran = false; - - @Override - public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) { - if (ran) { - plotPlayer.sendMessage("Already running!"); - return false; - } - if (strings.length != 2) { - plotPlayer.sendMessage( - "First make a backup of your world called then stand in the middle of an empty plot"); - plotPlayer.sendMessage("use /plot trimall "); - return false; - } - if (!WorldUtil.IMP.isWorld(strings[0])) { - Captions.NOT_VALID_PLOT_WORLD.send(plotPlayer, strings[0]); - return false; - } - ran = true; - TaskManager.IMP.async(new Runnable() { - @Override - public void run() { - try { - // TODO NOT IMPLEMENTED -// PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1])); -// Location loc = plotPlayer.getLocation(); -// trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4); -// trim.run(); -// plotPlayer.sendMessage("Done!"); - } catch (Throwable e) { - e.printStackTrace(); - } - ran = false; - } - }); - return true; - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSetBiome.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSetBiome.java deleted file mode 100644 index 3d8e1c8d3..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSetBiome.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.util.TaskManager; -import com.github.intellectualsites.plotsquared.commands.Command; -import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; -import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory; -import com.github.intellectualsites.plotsquared.plot.commands.MainCommand; -import com.github.intellectualsites.plotsquared.plot.commands.RequiredType; -import com.github.intellectualsites.plotsquared.plot.config.Captions; -import com.github.intellectualsites.plotsquared.plot.object.Plot; -import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; -import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; -import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; -import com.github.intellectualsites.plotsquared.plot.util.MainUtil; -import com.github.intellectualsites.plotsquared.plot.util.Permissions; -import com.github.intellectualsites.plotsquared.plot.util.StringMan; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.biome.Biomes; -import com.sk89q.worldedit.world.registry.BiomeRegistry; -import org.bukkit.Bukkit; - -import java.util.Collection; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ThreadLocalRandom; - -@CommandDeclaration( - command = "generatebiome", - permission = "plots.generatebiome", - category = CommandCategory.APPEARANCE, - requiredType = RequiredType.NONE, - description = "Generate a biome in your plot", - aliases = {"bg", "gb"}, - usage = "/plots generatebiome " -) -public class PlotSetBiome extends Command { - - public PlotSetBiome() { - super(MainCommand.getInstance(), true); - } - - @Override - public CompletableFuture execute( - final PlotPlayer player, - String[] args, - RunnableVal3 confirm, - RunnableVal2 whenDone - ) throws CommandException { - final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT); - checkTrue(plot.isOwner(player.getUUID()) || Permissions - .hasPermission(player, "plots.admin.command.generatebiome"), Captions.NO_PLOT_PERMS); - if (plot.getRunning() != 0) { - Captions.WAIT_FOR_TIMER.send(player); - return null; - } - checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage()); - final Set regions = plot.getRegions(); - BiomeRegistry biomeRegistry = WorldEdit - .getInstance() - .getPlatformManager() - .queryCapability(Capability.GAME_HOOKS) - .getRegistries() - .getBiomeRegistry(); - Collection knownBiomes = BiomeTypes.values(); - final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry); - if (biome == null) { - String biomes = StringMan - .join(BiomeType.REGISTRY.values(), Captions.BLOCK_LIST_SEPARATOR.getTranslated()); - Captions.NEED_BIOME.send(player); - MainUtil.sendMessage(player, Captions.SUBCOMMAND_SET_OPTIONS_HEADER + biomes); - return CompletableFuture.completedFuture(false); - } - confirm.run(this, () -> { - if (plot.getRunning() != 0) { - Captions.WAIT_FOR_TIMER.send(player); - return; - } - plot.addRunning(); - TaskManager.IMP.async(() -> { - EditSession session = WorldEdit.getInstance().newEditSessionBuilder().world(BukkitAdapter.adapt(Bukkit.getWorld( - plot.getArea().worldname))) - .checkMemory(false) - .allowedRegionsEverywhere() - .actor(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID()))) - .limitUnlimited() - .build(); - long seed = ThreadLocalRandom.current().nextLong(); - for (CuboidRegion region : regions) { - session.regenerate(region, biome, seed); - } - session.flushQueue(); - plot.removeRunning(); - }); - }, null); - - return CompletableFuture.completedFuture(true); - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java deleted file mode 100644 index 5a2b5484f..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java +++ /dev/null @@ -1,225 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.FaweAPI; -import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.regions.FaweMask; -import com.fastasyncworldedit.core.regions.FaweMaskManager; -import com.fastasyncworldedit.core.regions.RegionWrapper; -import com.github.intellectualsites.plotsquared.plot.commands.MainCommand; -import com.github.intellectualsites.plotsquared.plot.config.Settings; -import com.github.intellectualsites.plotsquared.plot.database.DBFunc; -import com.github.intellectualsites.plotsquared.plot.flag.Flags; -import com.github.intellectualsites.plotsquared.plot.listener.WEManager; -import com.github.intellectualsites.plotsquared.plot.object.Plot; -import com.github.intellectualsites.plotsquared.plot.object.PlotArea; -import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; -import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; -import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; -import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionIntersection; -import com.sk89q.worldedit.world.World; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; - -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -public class PlotSquaredFeature extends FaweMaskManager { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - public PlotSquaredFeature() { - super("PlotSquared"); - LOGGER.info("Optimizing PlotSquared"); - if (com.fastasyncworldedit.core.configuration.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_V4_HOOK) { - Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false; - try { - setupBlockQueue(); - setupSchematicHandler(); - setupChunkManager(); - } catch (Throwable ignored) { - LOGGER.info("Please update PlotSquared: https://www.spigotmc.org/resources/77506/"); - } - if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) { - new FaweTrim(); - } - if (MainCommand.getInstance().getCommand("generatebiome") == null) { - new PlotSetBiome(); - } - } - // TODO: revisit this later on - /* - try { - if (Settings.Enabled_Components.WORLDS) { - new ReplaceAll(); - } - } catch (Throwable e) { - log.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands"); - } - */ - } - - public static String getName(UUID uuid) { - return UUIDHandler.getName(uuid); - } - - private void setupBlockQueue() throws RuntimeException { - // If it's going to fail, throw an error now rather than later - //QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null); - //GlobalBlockQueue.IMP.setProvider(provider); - //HybridPlotManager.REGENERATIVE_CLEAR = false; - //log.debug(" - QueueProvider: " + FaweLocalBlockQueue.class); - //log.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR); - } - - private void setupChunkManager() throws RuntimeException { - ChunkManager.manager = new FaweChunkManager(ChunkManager.manager); - LOGGER.info(" - ChunkManager: {}", ChunkManager.manager); - } - - private void setupSchematicHandler() throws RuntimeException { - SchematicHandler.manager = new FaweSchematicHandler(); - LOGGER.info(" - SchematicHandler: {}", SchematicHandler.manager); - } - - public boolean isAllowed(Player player, Plot plot, MaskType type) { - if (plot == null) { - return false; - } - UUID uid = player.getUniqueId(); - if (Flags.NO_WORLDEDIT.isTrue(plot)) { - player.print(Caption.of( - "fawe.cancel.reason.no.region.reason", - Caption.of("fawe.cancel.reason.no.region.plot.noworldeditflag") - )); - return false; - } - if (plot.isOwner(uid) || player.hasPermission("fawe.plotsquared.admin")) { - return true; - } - if (type != MaskType.MEMBER) { - player.print(Caption.of( - "fawe.cancel.reason.no.region.reason", - Caption.of("fawe.cancel.reason.no.region.plot.owner.only") - )); - return false; - } - if (plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)) { - return true; - } - if (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) { - if (!player.hasPermission("fawe.plotsquared.member")) { - player.print(Caption.of( - "fawe.cancel.reason.no.region.reason", - Caption.of("fawe.error.no-perm", "fawe.plotsquared.member") - )); - return false; - } - if (!plot.getOwners().isEmpty() && plot.getOwners().stream().anyMatch(this::playerOnline)) { - return true; - } else { - player.print(Caption.of( - "fawe.cancel.reason.no.region.reason", - Caption.of("fawe.cancel.reason.no.region.plot.owner.offline") - )); - return false; - } - } - player.print(Caption.of( - "fawe.cancel.reason.no.region.reason", - Caption.of("fawe.cancel.reason.no.region.not.added") - )); - return false; - } - - private boolean playerOnline(UUID uuid) { - if (uuid == null) { - return false; - } - org.bukkit.entity.Player player = Bukkit.getPlayer(uuid); - return player != null && player.isOnline(); - } - - @Override - public FaweMask getMask(Player player, MaskType type) { - final PlotPlayer pp = PlotPlayer.wrap(player.getUniqueId()); - if (pp == null) { - return null; - } - final Set regions; - Plot plot = pp.getCurrentPlot(); - if (isAllowed(player, plot, type)) { - regions = plot.getRegions(); - } else { - plot = null; - regions = WEManager.getMask(pp); - if (regions.size() == 1) { - CuboidRegion region = regions.iterator().next(); - if (region.getMinimumPoint().getX() == Integer.MIN_VALUE && region - .getMaximumPoint() - .getX() == Integer.MAX_VALUE) { - regions.clear(); - } - } - } - if (regions.isEmpty()) { - return null; - } - PlotArea area = pp.getApplicablePlotArea(); - int min = area != null ? area.MIN_BUILD_HEIGHT : 0; - int max = area != null ? Math.min(255, area.MAX_BUILD_HEIGHT) : 255; - final HashSet faweRegions = new HashSet<>(); - for (CuboidRegion current : regions) { - faweRegions.add(new RegionWrapper( - current.getMinimumX(), - current.getMaximumX(), - min, - max, - current.getMinimumZ(), - current.getMaximumZ() - )); - } - final CuboidRegion region = regions.iterator().next(); - final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ()); - final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ()); - final Plot finalPlot = plot; - if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot) || regions.isEmpty()) { - return null; - } - - Region maskedRegion; - if (regions.size() == 1) { - maskedRegion = new CuboidRegion(pos1, pos2); - } else { - World world = FaweAPI.getWorld(area.worldname); - List weRegions = regions.stream() - .map(r -> new CuboidRegion( - world, - BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()), - BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ()) - )) - .collect(Collectors.toList()); - maskedRegion = new RegionIntersection(world, weRegions); - } - - return new FaweMask(maskedRegion) { - @Override - public boolean isValid(Player player, MaskType type) { - if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot)) { - return false; - } - return isAllowed(player, finalPlot, type); - } - }; - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitItemStack.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitItemStack.java index 9ec00af76..1eed3ad33 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitItemStack.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/BukkitItemStack.java @@ -34,7 +34,7 @@ public class BukkitItemStack extends BaseItemStack { @Nullable @Override public Object getNativeItem() { - ItemUtil util = Fawe.imp().getItemUtil(); + ItemUtil util = Fawe.platform().getItemUtil(); if (util != null && nativeItem == null) { return nativeItem = util.getNMSItem(stack); } @@ -58,7 +58,7 @@ public class BukkitItemStack extends BaseItemStack { public CompoundTag getNbtData() { if (!loadedNBT) { loadedNBT = true; - ItemUtil util = Fawe.imp().getItemUtil(); + ItemUtil util = Fawe.platform().getItemUtil(); if (util != null) { super.setNbtData(util.getNBT(stack)); } @@ -68,7 +68,7 @@ public class BukkitItemStack extends BaseItemStack { @Override public void setNbtData(@Nullable CompoundTag nbtData) { - ItemUtil util = Fawe.imp().getItemUtil(); + ItemUtil util = Fawe.platform().getItemUtil(); if (util != null) { stack = util.setNBT(stack, nbtData); nativeItem = null; diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java index cba863428..43fa6b0b6 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/MinecraftVersion.java @@ -12,6 +12,7 @@ public class MinecraftVersion implements Comparable { public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16); public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17); + public static final MinecraftVersion CAVES_18 = new MinecraftVersion(1, 18); private final int major; private final int minor; @@ -68,7 +69,7 @@ public class MinecraftVersion implements Comparable { * @param other The other version to compare against. * @return {@code true} if this version is higher or equal compared to the other version. */ - public boolean isEqualOrHigher(MinecraftVersion other) { + public boolean isEqualOrHigherThan(MinecraftVersion other) { return compareTo(other) >= 0; } @@ -76,7 +77,7 @@ public class MinecraftVersion implements Comparable { * @param other The other version to compare against. * @return {@code true} if this version is lower or equal compared to the other version. */ - public boolean isEqualOrLower(MinecraftVersion other) { + public boolean isEqualOrLowerThan(MinecraftVersion other) { return compareTo(other) <= 0; } @@ -84,7 +85,7 @@ public class MinecraftVersion implements Comparable { * @param other The other version to compare against. * @return {@code true} if this version is higher than the other version. */ - public boolean isHigher(MinecraftVersion other) { + public boolean isHigherThan(MinecraftVersion other) { return compareTo(other) > 0; } @@ -92,7 +93,7 @@ public class MinecraftVersion implements Comparable { * @param other The other version to compare against. * @return {@code true} if this version is lower than to the other version. */ - public boolean isLower(MinecraftVersion other) { + public boolean isLowerThan(MinecraftVersion other) { return compareTo(other) < 0; } @@ -139,6 +140,11 @@ public class MinecraftVersion implements Comparable { return getRelease() == that.getRelease(); } + @Override + public String toString() { + return major + "." + minor + "." + release; + } + /** * Determines the server version based on the CraftBukkit package path, e.g. {@code org.bukkit.craftbukkit.v1_16_R3}, * where v1_16_R3 is the resolved version. diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index ebf394d43..acfd5cacd 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -107,7 +107,7 @@ public class BukkitPlayer extends AbstractPlayerActor { this.player = player; //FAWE start this.permAttachment = plugin.getPermissionAttachmentManager().getOrAddAttachment(player); - if (player != null && Settings.IMP.CLIPBOARD.USE_DISK) { + if (player != null && Settings.settings().CLIPBOARD.USE_DISK) { BukkitPlayer cached = WorldEditPlugin.getInstance().getCachedPlayer(player); if (cached == null) { loadClipboardFromDisk(); @@ -169,7 +169,7 @@ public class BukkitPlayer extends AbstractPlayerActor { player.getInventory().setItemInMainHand(newItem); HashMap overflow = inv.addItem(item); if (!overflow.isEmpty()) { - TaskManager.IMP.sync(new RunnableVal<>() { + TaskManager.taskManager().sync(new RunnableVal<>() { @Override public void run(Object value) { for (Map.Entry entry : overflow.entrySet()) { @@ -243,7 +243,7 @@ public class BukkitPlayer extends AbstractPlayerActor { } org.bukkit.World finalWorld = world; //FAWE end - return TaskManager.IMP.sync(() -> player.teleport(new Location( + return TaskManager.taskManager().sync(() -> player.teleport(new Location( finalWorld, pos.getX(), pos.getY(), diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 83fc8c889..602ec139b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.bukkit; +import com.fastasyncworldedit.bukkit.util.MinecraftVersion; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.google.common.collect.Sets; import com.sk89q.bukkit.util.CommandInfo; @@ -274,9 +275,19 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser RelighterFactory getRelighterFactory() { if (this.relighterFactory == null) { this.relighterFactory = this.plugin.getBukkitImplAdapter().getRelighterFactory(); - LOGGER.info("Using " + this.relighterFactory.getClass().getCanonicalName() + " as relighter factory."); + LOGGER.info("Using {} as relighter factory.", this.relighterFactory.getClass().getCanonicalName()); } return this.relighterFactory; } + + @Override + public int versionMinY() { + return new MinecraftVersion().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? -64 : 0; + } + + @Override + public int versionMaxY() { + return new MinecraftVersion().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? 319 : 255; + } //FAWE end } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index cad10dd42..379476ec8 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -301,10 +301,10 @@ public class BukkitWorld extends AbstractWorld { if (treeTypeMapping.get(type) == null) { LOGGER.error("No TreeType mapping for TreeGenerator.TreeType." + type); //FAWE start - LOGGER.info("The above message is displayed because your FAWE version is newer than " + Bukkit.getVersion() + - " and contains features of future minecraft versions which do not exist in " - + Bukkit.getVersion() + ", hence the tree type " + type + " is not available. This is not an error. " + - "This version will work on your version of Minecraft. This is an informative message only"); + LOGGER.info("The above message is displayed because your FAWE version is newer than {}" + + " and contains features of future minecraft versions which do not exist in {} hence the tree type" + + "{} is not available. This is not an error. This version will work on your version of Minecraft." + + "This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); //FAWE end } } @@ -317,7 +317,7 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 pt) { //FAWE start - allow tree commands to be undone and obey region restrictions - return TaskManager.IMP.sync(() -> WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt, + return TaskManager.taskManager().sync(() -> WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt, getWorld() )); //FAWE end @@ -520,7 +520,7 @@ public class BukkitWorld extends AbstractWorld { public BaseBlock getFullBlock(BlockVector3 position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { - return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position)); + return adapter.getFullBlock(BukkitAdapter.adapt(getWorld(), position)); } else { return getBlock(position).toBaseBlock(); } @@ -555,7 +555,7 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean fullySupports3DBiomes() { // Supports if API does and we're not in the overworld - return HAS_3D_BIOMES && getWorld().getEnvironment() != World.Environment.NORMAL; + return HAS_3D_BIOMES && getWorld().getEnvironment() != World.Environment.NORMAL || PaperLib.isVersion(18); } @SuppressWarnings("deprecation") diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 6e93f0c19..37f743e1c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -138,12 +138,12 @@ public class WorldEditPlugin extends JavaPlugin { platform = new BukkitServerInterface(this, getServer()); worldEdit.getPlatformManager().register(platform); - //FAWE start - Rename config to config-legacy.yml TODO: Chose a better name in the future - createDefaultConfiguration("config-legacy.yml"); // Create the default configuration file for WorldEdit, for us it's 'config-legacy.yml' + //FAWE start - Migrate from config-legacy to worldedit-config + migrateLegacyConfig(); //FAWE end //FAWE start - Modify WorldEdit config name - config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config-legacy.yml"), true), this); + config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this); //FAWE end //FAWE start - Setup permission attachments @@ -220,8 +220,6 @@ public class WorldEditPlugin extends JavaPlugin { // Enable metrics new Metrics(this, BSTATS_ID); - // Check whether the server runs on 11 or greater - ServerLib.checkJavaLTS(); // Check if we are in a safe environment ServerLib.checkUnsafeForks(); // Check if a new build is available @@ -369,8 +367,8 @@ public class WorldEditPlugin extends JavaPlugin { } else { //FAWE start - Identify as FAWE LOGGER.info("FastAsyncWorldEdit could not find a Bukkit adapter for this MC version, " - + "but it seems that you have another implementation of FastAsyncWorldEdit installed (" + platform.getPlatformName() + ") " - + "that handles the world editing."); + + "but it seems that you have another implementation of FastAsyncWorldEdit installed ({}) " + + "that handles the world editing.", platform.getPlatformName()); //FAWE end } this.adapter.invalidate(); @@ -382,7 +380,7 @@ public class WorldEditPlugin extends JavaPlugin { */ @Override public void onDisable() { - Fawe.get().onDisable(); + Fawe.instance().onDisable(); WorldEdit worldEdit = WorldEdit.getInstance(); worldEdit.getSessionManager().unload(); if (platform != null) { @@ -424,6 +422,19 @@ public class WorldEditPlugin extends JavaPlugin { } } + private void migrateLegacyConfig() { + File legacy = new File(getDataFolder(), "config-legacy.yml"); + if (legacy.exists()) { + try { + legacy.renameTo(new File(getDataFolder(), "worldedit-config.yml")); + LOGGER.info("Migrated config-legacy.yml to worldedit-config.yml"); + } catch (Exception e) { + LOGGER.error("Unable to rename legacy config file", e); + } + } + createDefaultConfiguration("worldedit-config.yml"); + } + private void copyDefaultConfig(InputStream input, File actual, String name) { try (FileOutputStream output = new FileOutputStream(actual)) { byte[] buf = new byte[8192]; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 8f2e4008e..38fdbff91 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -106,7 +106,15 @@ public interface BukkitImplAdapter extends IBukkitAdapter { * @param location the location * @return the block */ - BaseBlock getBlock(Location location); + BlockState getBlock(Location location); + + /** + * Get the block at the given location. + * + * @param location the location + * @return the block + */ + BaseBlock getFullBlock(Location location); /** * Create a {@link WorldNativeAccess} for the given world reference. @@ -306,7 +314,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { @Nullable default World createWorld(WorldCreator creator) { - return ((FaweBukkit) Fawe.imp()).createWorldUnloaded(creator::createWorld); + return ((FaweBukkit) Fawe.platform()).createWorldUnloaded(creator::createWorld); } /** diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 3224aec12..11cee4f14 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.bukkit.adapter; +import com.fastasyncworldedit.bukkit.util.MinecraftVersion; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.util.io.Closer; import org.apache.logging.log4j.Logger; @@ -39,6 +40,8 @@ public class BukkitImplLoader { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final List adapterCandidates = new ArrayList<>(); + private final String minorMCVersion = String.valueOf(new MinecraftVersion().getMinor()); + private int zeroth = 0; private String customCandidate; private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl.fawe"; @@ -73,6 +76,7 @@ public class BukkitImplLoader { String className = System.getProperty("worldedit.bukkit.adapter"); if (className != null) { customCandidate = className; + zeroth = 1; adapterCandidates.add(className); LOGGER.info("-Dworldedit.bukkit.adapter used to add " + className + " to the list of available Bukkit adapters"); } @@ -101,7 +105,11 @@ public class BukkitImplLoader { int beginIndex = 0; int endIndex = className.length() - CLASS_SUFFIX.length(); className = className.substring(beginIndex, endIndex); - adapterCandidates.add(className); + if (className.contains(minorMCVersion)) { + adapterCandidates.add(zeroth, className); + } else { + adapterCandidates.add(className); + } } } finally { closer.close(); @@ -142,7 +150,11 @@ public class BukkitImplLoader { int beginIndex = 0; int endIndex = resource.length() - CLASS_SUFFIX.length(); String className = resource.substring(beginIndex, endIndex); - adapterCandidates.add(className); + if (className.contains(minorMCVersion)) { + adapterCandidates.add(zeroth, className); + } else { + adapterCandidates.add(className); + } } } diff --git a/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml b/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml similarity index 61% rename from worldedit-bukkit/src/main/resources/defaults/config-legacy.yml rename to worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml index 51817009c..8140cade6 100644 --- a/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml +++ b/worldedit-bukkit/src/main/resources/defaults/worldedit-config.yml @@ -10,39 +10,39 @@ # in categories, like "max-blocks-changed", are placed in the "limits" # category. # - If you want to check the format of this file before putting it -# into WorldEdit, paste it into http://yaml-online-parser.appspot.com/ +# into WorldEdit, paste it into https://yaml-online-parser.appspot.com/ # and see if it gives you "ERROR:". # - Lines starting with # are comments, so they are ignored. # - If you want to allow blocks, make sure to change "disallowed-blocks" to [] # -limits : - max-blocks-changed : +limits: + max-blocks-changed: # Ignored, use FAWE config limits - default : -1 - maximum : -1 - max-polygonal-points : - default : -1 - maximum : 20 - max-radius : -1 - max-super-pickaxe-size : 5 - max-brush-radius : 100 - butcher-radius : - default : -1 - maximum : -1 - disallowed-blocks : + default: -1 + maximum: -1 + max-polygonal-points: + default: -1 + maximum: 20 + max-radius: -1 + max-super-pickaxe-size: 5 + max-brush-radius: 100 + butcher-radius: + default: -1 + maximum: -1 + disallowed-blocks: - "minecraft:wheat" - "minecraft:fire" - "minecraft:redstone_wire" -use-inventory : - enable : false - allow-override : true - creative-mode-overrides : false +use-inventory: + enable: false + allow-override: true + creative-mode-overrides: false -logging : - log-commands : false - file : worldedit.log +logging: + log-commands: false + file: worldedit.log # The format of custom log message. This is java general format string (java.util.Formatter). Arguments are: # 1$ : date - a Date object representing event time of the log record. # 2$ : source - a string representing the caller, if available; otherwise, the logger's name. @@ -53,44 +53,44 @@ logging : # For details see: # https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html # https://docs.oracle.com/javase/8/docs/api/java/util/logging/SimpleFormatter.html#format-java.util.logging.LogRecord- - format : "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n" + format: "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n" -super-pickaxe : - drop-items : true - many-drop-items : false +super-pickaxe: + drop-items: true + many-drop-items: false -snapshots : - directory : +snapshots: + directory: -navigation-wand : - item : minecraft:compass - max-distance : 100 +navigation-wand: + item: minecraft:compass + max-distance: 100 -scripting : - timeout : 3000 - dir : craftscripts +scripting: + timeout: 3000 + dir: craftscripts -saving : - dir : schematics +saving: + dir: schematics -files : - allow-symbolic-links : false +files: + allow-symbolic-links: false -history : - size : 15 - expiration : 10 +history: + size: 15 + expiration: 10 -calculation : - timeout : 100 +calculation: + timeout: 100 -debugging : - trace-unflushed-sessions : false +debugging: + trace-unflushed-sessions: false -wand-item : minecraft:wooden_axe -shell-save-type : -no-double-slash : false -no-op-permissions : false -debug : false -show-help-on-first-use : true -server-side-cui : true -command-block-support : false +wand-item: minecraft:wooden_axe +shell-save-type: +no-double-slash: false +no-op-permissions: false +debug: false +show-help-on-first-use: true +server-side-cui: true +command-block-support: false diff --git a/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/MinecraftVersionTest.java b/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/MinecraftVersionTest.java index 561d2be37..9d54616d4 100644 --- a/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/MinecraftVersionTest.java +++ b/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/MinecraftVersionTest.java @@ -20,14 +20,14 @@ public class MinecraftVersionTest { @Test public void testEqualOrHigher() { - assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 3))); - assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 2))); - assertFalse(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 4))); + assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 3))); + assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 2))); + assertFalse(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 4))); } @Test public void testEqualOrHigherWithoutRelease() { - assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16))); + assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16))); } @Test @@ -39,15 +39,15 @@ public class MinecraftVersionTest { @Test public void testEqualOrLower() { - assertTrue(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 3))); - assertTrue(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 4))); - assertFalse(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 2))); + assertTrue(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 3))); + assertTrue(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 4))); + assertFalse(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 2))); } @Test public void testForChunkStretched() { - assertTrue(latestVersion.isEqualOrHigher(MinecraftVersion.NETHER)); - assertFalse(latestVersion.isLower(new MinecraftVersion(1, 14, 2))); + assertTrue(latestVersion.isEqualOrHigherThan(MinecraftVersion.NETHER)); + assertFalse(latestVersion.isLowerThan(new MinecraftVersion(1, 14, 2))); } } diff --git a/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/StubServer.java b/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/StubServer.java index 864f82a9f..237b55903 100644 --- a/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/StubServer.java +++ b/worldedit-bukkit/src/test/java/com/fastasyncworldedit/util/StubServer.java @@ -118,6 +118,11 @@ public class StubServer implements Server { return 0; } + @Override + public int getSimulationDistance() { + return 12; + } + @Override public @NotNull String getIp() { @@ -150,6 +155,26 @@ public class StubServer implements Server { return false; } + @Override + public @NotNull String getResourcePack() { + return null; + } + + @Override + public @NotNull String getResourcePackHash() { + return null; + } + + @Override + public @NotNull String getResourcePackPrompt() { + return null; + } + + @Override + public boolean isResourcePackRequired() { + return false; + } + @Override public boolean hasWhitelist() { return false; @@ -465,6 +490,11 @@ public class StubServer implements Server { } + @Override + public boolean getHideOnlinePlayers() { + return false; + } + @Override public boolean getOnlineMode() { return false; diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java index eb17c0f37..e9a397b73 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.AbstractPlatform; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; @@ -169,6 +170,16 @@ class CLIPlatform extends AbstractPlatform { return (_a, _b, _c) -> NullRelighter.INSTANCE; } + @Override + public int versionMinY() { + return dataVersion >= Constants.DATA_VERSION_MC_1_18 ? -64 : 0; + } + + @Override + public int versionMaxY() { + return dataVersion >= Constants.DATA_VERSION_MC_1_18 ? 319 : 255; + } + public void addWorld(World world) { worlds.add(world); } diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java index a9a57877a..73eb307ec 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java @@ -190,7 +190,7 @@ public class CLIWorldEdit { this.commandSender = new CLICommandSender(this, LOGGER); this.platform = new CLIPlatform(this); //FAWE start - identify as Fawe - LOGGER.info("FastAsyncWorldEdit CLI (version " + getInternalVersion() + ") is loaded"); + LOGGER.info("FastAsyncWorldEdit CLI (version {}) is loaded", getInternalVersion()); //FAWE end } diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 3d73c711b..7e4ae09a7 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -12,7 +12,7 @@ applyPlatformAndCoreConfiguration() dependencies { constraints { implementation("org.yaml:snakeyaml") { - version { strictly("1.28") } + version { strictly("1.30") } because("Bukkit provides SnakeYaml") } } @@ -37,7 +37,6 @@ dependencies { // Plugins compileOnly(libs.redprotect) { isTransitive = false } - compileOnly(libs.plotsquaredV4) { isTransitive = false } compileOnly(libs.plotsquaredV6Core) { isTransitive = false } // ensure this is on the classpath for the AP diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index cdb07e08f..8f4555040 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.5.0-RC" + kotlin("jvm") version "1.5.30" application } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java index 01b602e24..6163a94ce 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/Fawe.java @@ -101,17 +101,17 @@ public class Fawe { this.setupConfigs(); TaskManager.IMP = this.implementation.getTaskManager(); - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { MainUtil.deleteOlder( MainUtil.getFile(this.implementation - .getDirectory(), Settings.IMP.PATHS.HISTORY), - TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS), + .getDirectory(), Settings.settings().PATHS.HISTORY), + TimeUnit.DAYS.toMillis(Settings.settings().HISTORY.DELETE_AFTER_DAYS), false ); MainUtil.deleteOlder( MainUtil.getFile(this.implementation - .getDirectory(), Settings.IMP.PATHS.CLIPBOARD), - TimeUnit.DAYS.toMillis(Settings.IMP.CLIPBOARD.DELETE_AFTER_DAYS), + .getDirectory(), Settings.settings().PATHS.CLIPBOARD), + TimeUnit.DAYS.toMillis(Settings.settings().CLIPBOARD.DELETE_AFTER_DAYS), false ); }); @@ -123,28 +123,49 @@ public class Fawe { this.timer = new FaweTimer(); // Delayed worldedit setup - TaskManager.IMP.later(() -> { + TaskManager.taskManager().later(() -> { try { - WEManager.IMP.addManagers(Fawe.this.implementation.getMaskManagers()); + WEManager.weManager().addManagers(Fawe.this.implementation.getMaskManagers()); } catch (Throwable ignored) { } }, 0); - TaskManager.IMP.repeat(timer, 1); + TaskManager.taskManager().repeat(timer, 1); } /** * Get the implementation specific class. + * @deprecated use {@link #platform()} */ @SuppressWarnings("unchecked") + @Deprecated(forRemoval = true, since = "2.0.0") public static T imp() { return instance != null ? (T) instance.implementation : null; } + /** + * Get the implementation specific class. + * @since 2.0.0 + */ + @SuppressWarnings("unchecked") + public static T platform() { + return instance != null ? (T) instance.implementation : null; + } + + + /** + * Get the implementation independent class. + * @deprecated use {@link #instance()} + */ + @Deprecated(forRemoval = true, since = "2.0.0") + public static Fawe get() { + return instance; + } + /** * Get the implementation independent class. */ - public static Fawe get() { + public static Fawe instance() { return instance; } @@ -225,8 +246,8 @@ public class Fawe { } public void onDisable() { - if (imp().getPreloader(false) != null) { - imp().getPreloader(false).cancel(); + if (platform().getPreloader(false) != null) { + platform().getPreloader(false).cancel(); } } @@ -296,7 +317,7 @@ public class Fawe { MainUtil.copyFile(MainUtil.getJarFile(), "lang/strings.json", null); // Setting up config.yml File file = new File(this.implementation.getDirectory(), "config.yml"); - Settings.IMP.PLATFORM = implementation.getPlatform().replace("\"", ""); + Settings.settings().PLATFORM = implementation.getPlatform().replace("\"", ""); try (InputStream stream = getClass().getResourceAsStream("/fawe.properties"); BufferedReader br = new BufferedReader(new InputStreamReader(stream))) { String versionString = br.readLine(); @@ -304,17 +325,17 @@ public class Fawe { String dateString = br.readLine(); br.close(); this.version = FaweVersion.tryParse(versionString, commitString, dateString); - Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toString(); - Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-1.17/" + version.build; - Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash); + Settings.settings().DATE = new Date(100 + version.year, version.month, version.day).toString(); + Settings.settings().BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit/" + version.build; + Settings.settings().COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash); } catch (Throwable ignored) { } try { - Settings.IMP.reload(file); + Settings.settings().reload(file); } catch (Throwable e) { LOGGER.error("Failed to load config.", e); } - Settings.IMP.QUEUE.TARGET_SIZE = Math.max(Settings.IMP.QUEUE.TARGET_SIZE, Settings.IMP.QUEUE.PARALLEL_THREADS); + Settings.settings().QUEUE.TARGET_SIZE = Math.max(Settings.settings().QUEUE.TARGET_SIZE, Settings.settings().QUEUE.PARALLEL_THREADS); try { byte[] in = new byte[0]; byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in); @@ -332,14 +353,14 @@ public class Fawe { assert (Zstd.decompress(ob, compressed) == 0); LOGGER.info("ZSTD Compression Binding loaded successfully"); } catch (Throwable e) { - if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.IMP.HISTORY.COMPRESSION_LEVEL > 6) { - Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL); - Settings.IMP.HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.HISTORY.COMPRESSION_LEVEL); + if (Settings.settings().CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.settings().HISTORY.COMPRESSION_LEVEL > 6) { + Settings.settings().CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.settings().CLIPBOARD.COMPRESSION_LEVEL); + Settings.settings().HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.settings().HISTORY.COMPRESSION_LEVEL); LOGGER.error("ZSTD Compression Binding Not Found.\n" + "FAWE will still work but compression won't work as well.", e); } } - Settings.IMP.save(file); + Settings.settings().save(file); } public WorldEdit getWorldEdit() { @@ -347,7 +368,7 @@ public class Fawe { } private void setupMemoryListener() { - if (Settings.IMP.MAX_MEMORY_PERCENT < 1 || Settings.IMP.MAX_MEMORY_PERCENT > 99) { + if (Settings.settings().MAX_MEMORY_PERCENT < 1 || Settings.settings().MAX_MEMORY_PERCENT > 99) { return; } try { @@ -371,7 +392,7 @@ public class Fawe { if (max < 0) { continue; } - final long alert = (max * Settings.IMP.MAX_MEMORY_PERCENT) / 100; + final long alert = (max * Settings.settings().MAX_MEMORY_PERCENT) / 100; mp.setUsageThreshold(alert); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index 3c94233ee..fcaf33288 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; import com.fastasyncworldedit.core.regions.FaweMaskManager; import com.fastasyncworldedit.core.regions.RegionWrapper; -import com.fastasyncworldedit.core.util.EditSessionBuilder; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MemUtil; import com.fastasyncworldedit.core.util.TaskManager; @@ -60,24 +59,13 @@ public class FaweAPI { private static final Logger LOGGER = LogManagerCompat.getLogger(); - /** - * Offers a lot of options for building an EditSession. - * - * @return A new EditSessionBuilder - * @deprecated See {@link WorldEdit#newEditSessionBuilder()} - */ - @Deprecated(forRemoval = true) - public static EditSessionBuilder getEditSessionBuilder(World world) { - return new EditSessionBuilder(world); - } - /** * The TaskManager has some useful methods for doing things asynchronously. * * @return TaskManager */ public static TaskManager getTaskManager() { - return TaskManager.IMP; + return TaskManager.taskManager(); } /** @@ -93,7 +81,7 @@ public class FaweAPI { * @return the queue extent */ public static IQueueExtent createQueue(World world, boolean autoQueue) { - IQueueExtent queue = Fawe.get().getQueueHandler().getQueue(world); + IQueueExtent queue = Fawe.instance().getQueueHandler().getQueue(world); if (!autoQueue) { queue.disableQueue(); } @@ -139,7 +127,7 @@ public class FaweAPI { * @return Set of FaweMaskManager */ public static Set getMaskManagers() { - return new HashSet<>(WEManager.IMP.getManagers()); + return new HashSet<>(WEManager.weManager().getManagers()); } /** @@ -155,7 +143,7 @@ public class FaweAPI { * Get a player's allowed WorldEdit region(s). */ public static Region[] getRegions(Player player) { - return WEManager.IMP.getMask(player); + return WEManager.weManager().getMask(player); } /** @@ -167,7 +155,7 @@ public class FaweAPI { * @return array of allowed regions if whitelist, else of disallowed regions. */ public static Region[] getRegions(Player player, FaweMaskManager.MaskType type, boolean isWhiteList) { - return WEManager.IMP.getMask(player, type, isWhiteList); + return WEManager.weManager().getMask(player, type, isWhiteList); } /** @@ -182,13 +170,13 @@ public class FaweAPI { */ public static void cancelEdit(AbstractDelegateExtent extent, Component reason) { try { - WEManager.IMP.cancelEdit(extent, new FaweException(reason)); + WEManager.weManager().cancelEdit(extent, new FaweException(reason)); } catch (WorldEditException ignored) { } } public static void addMaskManager(FaweMaskManager maskMan) { - WEManager.IMP.addManager(maskMan); + WEManager.weManager().addManager(maskMan); } /** @@ -198,7 +186,7 @@ public class FaweAPI { if (!file.exists() || file.isDirectory()) { throw new IllegalArgumentException("Not a file!"); } - if (Settings.IMP.HISTORY.USE_DISK) { + if (Settings.settings().HISTORY.USE_DISK) { throw new IllegalArgumentException("History on disk not enabled!"); } if (!file.getName().toLowerCase(Locale.ROOT).endsWith(".bd")) { @@ -236,11 +224,10 @@ public class FaweAPI { */ public static List getBDFiles(Location origin, UUID user, int radius, long timediff, boolean shallow) { Extent extent = origin.getExtent(); - if (!(extent instanceof World)) { + if (!(extent instanceof World world)) { throw new IllegalArgumentException("Origin is not a valid world"); } - World world = (World) extent; - File history = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName()); + File history = MainUtil.getFile(Fawe.platform().getDirectory(), Settings.settings().PATHS.HISTORY + File.separator + world.getName()); if (!history.exists()) { return new ArrayList<>(); } @@ -364,12 +351,12 @@ public class FaweAPI { World unwrapped = WorldWrapper.unwrap(world); if (unwrapped instanceof IQueueExtent) { queue = (IQueueExtent) unwrapped; - } else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1) { + } else if (Settings.settings().QUEUE.PARALLEL_THREADS > 1) { ParallelQueueExtent parallel = - new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, true); + new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, true); queue = parallel.getExtent(); } else { - queue = Fawe.get().getQueueHandler().getQueue(world); + queue = Fawe.instance().getQueueHandler().getQueue(world); } } @@ -384,7 +371,7 @@ public class FaweAPI { } } if (mode != RelightMode.NONE) { - if (Settings.IMP.LIGHTING.REMOVE_FIRST) { + if (Settings.settings().LIGHTING.REMOVE_FIRST) { relighter.removeAndRelight(true); } else { relighter.fixSkyLighting(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 317d2df83..087402810 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -59,7 +59,15 @@ import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkNotNull; public enum FaweCache implements Trimable { - IMP; // singleton + /** + * @deprecated Use {@link #INSTANCE} to get an instance. + */ + @Deprecated(forRemoval = true, since = "2.0.0") + IMP, + /** + * @since 2.0.0 + */ + INSTANCE; private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -301,7 +309,7 @@ public enum FaweCache implements Trimable { // BlockStates int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) { bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry } else { bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries @@ -387,7 +395,7 @@ public enum FaweCache implements Trimable { // BlockStates int bitsPerEntry = MathMan.log2nlz(num_palette - 1); - if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) { bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry } else { bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries @@ -568,7 +576,7 @@ public enum FaweCache implements Trimable { Thread stuff */ public ThreadPoolExecutor newBlockingExecutor() { - int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS; + int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS; ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads, true); return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue, @@ -609,7 +617,7 @@ public enum FaweCache implements Trimable { lastException = hash; LOGGER.catching(throwable); count = 0; - } else if (count < Settings.IMP.QUEUE.PARALLEL_THREADS) { + } else if (count < Settings.settings().QUEUE.PARALLEL_THREADS) { LOGGER.warn(throwable.getMessage()); count++; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweVersion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweVersion.java index 344a9d401..6ce56a244 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweVersion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweVersion.java @@ -1,5 +1,9 @@ package com.fastasyncworldedit.core; +import com.fastasyncworldedit.core.util.StringMan; + +import java.util.Locale; + /** * An internal FAWE class not meant for public use. **/ @@ -10,28 +14,35 @@ public class FaweVersion { public final int day; public final int hash; public final int build; + public final int[] semver; + public final boolean snapshot; - public FaweVersion(int year, int month, int day, int hash, int build) { + public FaweVersion(int year, int month, int day, int[] semver, boolean snapshot, int hash, int build) { this.year = year; this.month = month; this.day = day; this.hash = hash; this.build = build; + this.semver = semver; + this.snapshot = snapshot; } public FaweVersion(String version, String commit, String date) { String[] split = version.substring(version.indexOf('=') + 1).split("-"); - int build = 0; - try { - build = Integer.parseInt(split[1]); - } catch (NumberFormatException ignored) { + String[] split1 = split[0].split("\\."); + int[] ver = new int[3]; + for (int i = 0; i < 3; i++) { + ver[i] = Integer.parseInt(split1[i]); } - this.build = build; + this.semver = ver; + this.snapshot = split.length > 1 && split[1].toLowerCase(Locale.ROOT).contains("snapshot"); + int buildIndex = this.snapshot ? 2 : 1; + this.build = split.length == buildIndex + 1 ? Integer.parseInt(split[buildIndex]) : 0; this.hash = Integer.parseInt(commit.substring(commit.indexOf('=') + 1), 16); - String[] split1 = date.substring(date.indexOf('=') + 1).split("\\."); - this.year = Integer.parseInt(split1[0]); - this.month = Integer.parseInt(split1[1]); - this.day = Integer.parseInt(split1[2]); + String[] split2 = date.substring(date.indexOf('=') + 1).split("\\."); + this.year = Integer.parseInt(split2[0]); + this.month = Integer.parseInt(split2[1]); + this.day = Integer.parseInt(split2[2]); } public static FaweVersion tryParse(String version, String commit, String date) { @@ -39,28 +50,42 @@ public class FaweVersion { return new FaweVersion(version, commit, date); } catch (Exception exception) { exception.printStackTrace(); - return new FaweVersion(0, 0, 0, 0, 0); + return new FaweVersion(0, 0, 0, null, true, 0, 0); } } @Override public String toString() { - if (hash == 0 && build == 0) { - return getSimpleVersionName() + "-NoVer-SNAPSHOT"; + if (semver == null) { + return "FastAsyncWorldEdit-NoVer-SNAPSHOT"; } else { - return getSimpleVersionName() + "-" + build; + String snapshot = this.snapshot ? "-SNAPSHOT" : ""; + String build = this.build > 0 ? "-" + this.build : ""; + return "FastAsyncWorldEdit-" + StringMan.join(semver, ".") + snapshot + build; } } /** - * @return The qualified version name + * Returns if another FaweVersion is newer than this one */ - public String getSimpleVersionName() { - return "FastAsyncWorldEdit-1.17"; - } - public boolean isNewer(FaweVersion other) { - return other.build < this.build; + if (other.semver == null) { + return other.build > this.build; + } + if (this.semver == null) { + return true; + } + if (other.semver[0] != this.semver[0]) { + return other.semver[0] > this.semver[0]; + } else if (other.semver[1] != this.semver[1]) { + return other.semver[1] > this.semver[1]; + } else if (other.semver[2] != this.semver[2]) { + return other.semver[2] > this.semver[2]; + } + if (other.snapshot == this.snapshot) { + return other.build > this.build; + } + return !other.snapshot; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/AnvilCommands.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/AnvilCommands.java index 71438bfd0..5c5ad228c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/AnvilCommands.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/AnvilCommands.java @@ -531,7 +531,7 @@ public class AnvilCommands { // }); // if (useData) { // for (long[] c : map) { - // BaseBlock block = FaweCache.IMP.CACHE_BLOCK[(int) c[0]]; + // BaseBlock block = FaweCache.INSTANCE.CACHE_BLOCK[(int) c[0]]; // String name = BlockType.fromID(block.getId()).getName(); // String str = String.format("%-7s (%.3f%%) %s #%d:%d", // String.valueOf(c[1]), diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/CFICommands.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/CFICommands.java index 932fc1495..d7c4afb82 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/CFICommands.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/CFICommands.java @@ -147,7 +147,7 @@ // CFISettings settings = getSettings(player).remove(); // generator.setPacketViewer(player); // settings.setGenerator(generator).bind(); -// generator.setImageViewer(Fawe.imp().getImageViewer(player)); +// generator.setImageViewer(Fawe.platform().getImageViewer(player)); // generator.update(); // mainMenu(player); // } @@ -226,7 +226,7 @@ // World world = FaweAPI.getWorld(folder.getName()); // if (world != null) { // if (player.getWorld() != world) { -// TaskManager.IMP.sync(new RunnableVal() { +// TaskManager.taskManager().sync(new RunnableVal() { // @Override // public void run(Object value) { // Location spawn = new Location(world, world.getSpawnPosition().toVector3()); @@ -425,7 +425,7 @@ // switch (argOpt.toLowerCase(Locale.ROOT)) { // case "true": // case "*": { -// generator.setTextureUtil(Fawe.get().getTextureUtil()); +// generator.setTextureUtil(Fawe.instance().getTextureUtil()); // return; // } // case "#clipboard": { @@ -453,7 +453,7 @@ // parserContext.setExtent(extent); // Request.request().setExtent(extent); // Mask mask = worldEdit.getMaskFactory().parseFromInput(argOpt, parserContext); -// TextureUtil tu = Fawe.get().getTextureUtil(); +// TextureUtil tu = Fawe.instance().getTextureUtil(); // for (int typeId : tu.getValidBlockIds()) { // BlockType type = BlockTypes.get(typeId); // extent.init(0, 0, 0, type.getDefaultState().toBaseBlock()); @@ -464,7 +464,7 @@ // break; // } // } -// generator.setTextureUtil(new FilteredTextureUtil(Fawe.get().getTextureUtil(), blocks)); +// generator.setTextureUtil(new FilteredTextureUtil(Fawe.instance().getTextureUtil(), blocks)); // coloring(player); // } // @@ -493,9 +493,9 @@ // public void complexity(Player player, int min, int max) throws FileNotFoundException { // HeightMapMCAGenerator gen = assertSettings(player).getGenerator(); // if (min == 0 && max == 100) { -// gen.setTextureUtil(Fawe.get().getTextureUtil()); +// gen.setTextureUtil(Fawe.instance().getTextureUtil()); // } else { -// gen.setTextureUtil(new CleanTextureUtil(Fawe.get().getTextureUtil(), min, max)); +// gen.setTextureUtil(new CleanTextureUtil(Fawe.instance().getTextureUtil(), min, max)); // } // coloring(player); // } @@ -1201,7 +1201,7 @@ // whiteOnly = true; // maskArg = null; // imageMaskArg = null; -// generator.setTextureUtil(Fawe.get().getTextureUtil()); +// generator.setTextureUtil(Fawe.instance().getTextureUtil()); // } // // public void resetComponent() { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/ListFilters.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/ListFilters.java index ebb75b247..aa9556937 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/ListFilters.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/ListFilters.java @@ -95,7 +95,7 @@ public class ListFilters { } String firstArg = finalArg.substring(0, finalArg.length() - File.separator.length()); if (firstArg.length() > 3 && firstArg.length() <= 16) { - UUID fromName = Fawe.imp().getUUID(finalArg); + UUID fromName = Fawe.platform().getUUID(finalArg); if (fromName != null) { newRoot = new File(root, finalArg); if (newRoot.exists()) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PlotLoader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PlotLoader.java index fe4242243..fba983d93 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PlotLoader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/PlotLoader.java @@ -45,7 +45,7 @@ // PlotPlayer player = PlotPlayer.get(actor.getName()); // // actor.print("Claiming world"); -// Plot plot = TaskManager.IMP.sync(new RunnableVal() { +// Plot plot = TaskManager.taskManager().sync(new RunnableVal() { // @Override // public void run(Plot o) { // int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() @@ -73,7 +73,7 @@ // File folder = CFICommands.getFolder(plot.getWorldName()); // Boolean result = createTask.apply(folder); // if (result == Boolean.TRUE) { -// TaskManager.IMP.sync(() -> plot.teleportPlayer(player)); +// TaskManager.taskManager().sync(() -> plot.teleportPlayer(player)); // } // return; // } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BrushSettings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BrushSettings.java index 2a18f856a..0a4d611bb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BrushSettings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BrushSettings.java @@ -90,7 +90,7 @@ public class BrushSettings { // } // if (settings.containsKey(SettingType.TRANSFORM.name())) { // String transformArgs = (String) settings.get(SettingType.TRANSFORM.name()); - // ResettableExtent extent = Fawe.get().getTransformParser().parseFromInput(transformArgs, parserContext); + // ResettableExtent extent = Fawe.instance().getTransformParser().parseFromInput(transformArgs, parserContext); // bs.setTransform(extent); // bs.constructor.put(SettingType.TRANSFORM, transformArgs); // } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java index d9f11976a..f0de661a1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/InspectBrush.java @@ -68,7 +68,7 @@ public class InspectBrush extends BrushTool { player.print(Caption.of("fawe.error.no-perm", "worldedit.tool.inspect")); return false; } - if (!Settings.IMP.HISTORY.USE_DATABASE) { + if (!Settings.settings().HISTORY.USE_DATABASE) { player.print(Caption.of( "fawe.error.setting.disable", "history.use-database (Import with /history import )" @@ -81,7 +81,7 @@ public class InspectBrush extends BrushTool { final int y = target.getBlockY(); final int z = target.getBlockZ(); World world = player.getWorld(); - RollbackDatabase db = DBHandler.IMP.getDatabase(world); + RollbackDatabase db = DBHandler.dbHandler().getDatabase(world); int count = 0; for (Supplier supplier : db.getEdits(target, false)) { count++; @@ -95,7 +95,7 @@ public class InspectBrush extends BrushTool { int from = change.from; int to = change.to; UUID uuid = edit.getUUID(); - String name = Fawe.imp().getName(uuid); + String name = Fawe.platform().getName(uuid); int index = edit.getIndex(); long age = System.currentTimeMillis() - edit.getBDFile().lastModified(); String ageFormatted = MainUtil.secToTime(age / 1000); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index aa6d4dda0..83dd34d95 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -34,7 +34,7 @@ public class Config { /** * Get the value for a node. Probably throws some error if you try to get a non-existent key. */ - private T get(String key, Class root) { + private T get(String key, Class root) { String[] split = key.split("\\."); Object instance = getInstance(split, root); if (instance != null) { @@ -57,7 +57,7 @@ public class Config { * @param key config node * @param value value */ - private void set(String key, Object value, Class root) { + private void set(String key, Object value, Class root) { String[] split = key.split("\\."); Object instance = getInstance(split, root); if (instance != null) { @@ -201,7 +201,7 @@ public class Config { /** * Get the static fields in a section. */ - private Map getFields(Class clazz) { + private Map getFields(Class clazz) { HashMap map = new HashMap<>(); for (Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) { @@ -223,12 +223,11 @@ public class Config { } StringBuilder m = new StringBuilder(); for (Object obj : listValue) { - m.append(System.lineSeparator() + spacing + "- " + toYamlString(obj, spacing)); + m.append(System.lineSeparator()).append(spacing).append("- ").append(toYamlString(obj, spacing)); } return m.toString(); } - if (value instanceof String) { - String stringValue = (String) value; + if (value instanceof String stringValue) { if (stringValue.isEmpty()) { return "''"; } @@ -237,11 +236,11 @@ public class Config { return value != null ? value.toString() : "null"; } - private void save(PrintWriter writer, Class clazz, final Object instance, int indent) { + private void save(PrintWriter writer, Class clazz, final Object instance, int indent) { try { String CTRF = System.lineSeparator(); String spacing = StringMan.repeat(" ", indent); - HashMap instances = new HashMap<>(); + HashMap, Object> instances = new HashMap<>(); for (Field field : clazz.getFields()) { if (field.getAnnotation(Ignore.class) != null) { continue; @@ -272,7 +271,7 @@ public class Config { configBlock = new ConfigBlock(); field.set(instance, configBlock); for (String blockName : blockNames.value()) { - configBlock.put(blockName, current.newInstance()); + configBlock.put(blockName, current.getDeclaredConstructor().newInstance()); } } // Save each instance @@ -299,11 +298,10 @@ public class Config { } writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); if (value == null) { - field.set(instance, value = current.newInstance()); + field.set(instance, value = current.getDeclaredConstructor().newInstance()); instances.put(current, value); } save(writer, current, value, indent + 2); - continue; } else { writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString( field.get(instance), @@ -321,7 +319,7 @@ public class Config { * * @param split the node (split by period) */ - private Field getField(String[] split, Class root) { + private Field getField(String[] split, Class root) { Object instance = getInstance(split, root); if (instance == null) { return null; @@ -352,74 +350,64 @@ public class Config { } } - private Object getInstance(Object instance, Class clazz) throws IllegalAccessException, InstantiationException { - try { - Field instanceField = clazz.getDeclaredField(clazz.getSimpleName()); - } catch (Throwable ignored) { - } - return clazz.newInstance(); - } - /** * Get the instance for a specific config node. * * @param split the node (split by period) * @return The instance or null */ - private Object getInstance(String[] split, Class root) { + private Object getInstance(String[] split, Class root) { try { Class clazz = root == null ? MethodHandles.lookup().lookupClass() : root; Object instance = this; while (split.length > 0) { - switch (split.length) { - case 1: - return instance; - default: - Class found = null; - Class[] classes = clazz.getDeclaredClasses(); - for (Class current : classes) { - if (StringMan.isEqual(current.getSimpleName(), toFieldName(split[0]))) { - found = current; - break; - } - } - try { - Field instanceField = clazz.getDeclaredField(toFieldName(split[0])); - setAccessible(instanceField); - if (instanceField.getType() != ConfigBlock.class) { - Object value = instanceField.get(instance); - if (value == null) { - value = found.newInstance(); - instanceField.set(instance, value); - } - clazz = found; - instance = value; - split = Arrays.copyOfRange(split, 1, split.length); - continue; - } - ConfigBlock value = (ConfigBlock) instanceField.get(instance); - if (value == null) { - value = new ConfigBlock(); - instanceField.set(instance, value); - } - instance = value.get(split[1]); - if (instance == null) { - instance = found.newInstance(); - value.put(split[1], instance); - } - clazz = found; - split = Arrays.copyOfRange(split, 2, split.length); - continue; - } catch (NoSuchFieldException ignored) { - } - if (found != null) { - split = Arrays.copyOfRange(split, 1, split.length); - clazz = found; - instance = clazz.newInstance(); - continue; - } - return null; + if (split.length == 1) { + return instance; } + Class found = null; + Class[] classes = clazz.getDeclaredClasses(); + for (Class current : classes) { + if (StringMan.isEqual(current.getSimpleName(), toFieldName(split[0]))) { + found = current; + break; + } + } + try { + Field instanceField = clazz.getDeclaredField(toFieldName(split[0])); + setAccessible(instanceField); + if (instanceField.getType() != ConfigBlock.class) { + Object value = instanceField.get(instance); + if (value == null) { + value = found.getDeclaredConstructor().newInstance(); + instanceField.set(instance, value); + } + clazz = found; + instance = value; + split = Arrays.copyOfRange(split, 1, split.length); + continue; + } + ConfigBlock value = (ConfigBlock) instanceField.get(instance); + if (value == null) { + value = new ConfigBlock(); + instanceField.set(instance, value); + } + instance = value.get(split[1]); + if (instance == null) { + instance = found.getDeclaredConstructor().newInstance(); + value.put(split[1], instance); + } + clazz = found; + split = Arrays.copyOfRange(split, 2, split.length); + continue; + } catch (NoSuchFieldException ignored) { + } + if (found != null) { + split = Arrays.copyOfRange(split, 1, split.length); + clazz = found; + instance = clazz.getDeclaredConstructor().newInstance(); + continue; + } + return null; } } catch (Throwable e) { e.printStackTrace(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 19b574108..4b43c0376 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -19,12 +19,16 @@ import java.util.stream.Stream; public class Settings extends Config { + /** + * @deprecated Use {@link #settings()} instead to get an instance. + */ @Ignore + @Deprecated(forRemoval = true, since = "2.0.0") public static final Settings IMP = new Settings(); - + @Ignore + static Settings INSTANCE = new Settings(); @Ignore public boolean PROTOCOL_SUPPORT_FIX = false; - @Comment("These first 6 aren't configurable") // This is a comment @Final // Indicates that this value isn't configurable public String ISSUES = "https://github.com/IntellectualSites/FastAsyncWorldEdit/issues"; @@ -38,7 +42,6 @@ public class Settings extends Config { public String COMMIT; // These values are set from FAWE before loading @Final public String PLATFORM; // These values are set from FAWE before loading - @Comment({ "Set true to enable WorldEdit restrictions per region (e.g. PlotSquared or WorldGuard).", "To be allowed to WorldEdit in a region, users need the appropriate", @@ -51,7 +54,6 @@ public class Settings extends Config { " - Disable with 100 or -1." }) public int MAX_MEMORY_PERCENT = 95; - @Create public ENABLED_COMPONENTS ENABLED_COMPONENTS; @Create @@ -63,8 +65,6 @@ public class Settings extends Config { @Create public WEB WEB; @Create - public PLOTSQUARED_INTEGRATION PLOTSQUARED_INTEGRATION; - @Create public EXTENT EXTENT; @Create public EXPERIMENTAL EXPERIMENTAL; @@ -79,513 +79,18 @@ public class Settings extends Config { @Create public ConfigBlock LIMITS; - @Comment("Enable or disable core components") - public static final class ENABLED_COMPONENTS { - - public boolean COMMANDS = true; - @Comment({ - "Disable the FAWE-PlotSquared hook to take over most intense P2 queueing", - "Specific aspects can be turned on and off further below", - "Only disables/enables the hook with v4. For v6, see PlotSquared settings.yml" - }) - public boolean PLOTSQUARED_V4_HOOK = true; - @Comment({"Show additional information in console. It helps us at IntellectualSites to find out more about an issue.", - "Leave it off if you don't need it, it can spam your console."}) - public boolean DEBUG = false; - @Comment({"Whether or not FAWE should notify you on startup about new versions available."}) - public boolean UPDATE_NOTIFICATIONS = true; - + private Settings() { + INSTANCE = this; } - @Comment("Paths for various directories") - public static final class PATHS { - - @Comment({ - "Put any minecraft or mod jars for FAWE to be aware of block textures", - }) - public String TEXTURES = "textures"; - public String HEIGHTMAP = "heightmap"; - public String HISTORY = "history"; - @Comment({ - "Multiple servers can use the same clipboards", - " - Use a shared directory or NFS/Samba" - }) - public String CLIPBOARD = "clipboard"; - @Comment("Each player has his or her own sub directory for schematics") - public boolean PER_PLAYER_SCHEMATICS = false; - - } - - @Comment("Region restriction settings") - public static final class REGION_RESTRICTIONS_OPTIONS { - - @Comment({ - "What type of users are allowed to WorldEdit in a region", - " - MEMBER = Players added to a region", - " - OWNER = Players who own the region" - }) - public String MODE = "MEMBER"; - @Comment({ - "Allow region blacklists.", - " - Currently only implemented for WorldGuard", - " - see region-restrictions-options.worldguard-region-blacklist" - }) - public boolean ALLOW_BLACKLISTS = false; - @Comment({ - "List of plugin mask managers that should be exclusive. Exclusive managers are not ", - "checked for edit restrictions if another manager already allowed an edit, and further ", - "managers are not checked if an exclusive manager allows an edit.", - " - May be useful to add PlotSquared if using both P2 and WorldGuard on a server", - " - Some custom-implementations in other plugins may override this setting" - }) - public List EXCLUSIVE_MANAGERS = new ArrayList<>(Collections.singleton(("ExamplePlugin"))); - @Comment({ - "If a worldguard-protected world should be considered as a region blacklist.", - " - This will create a blacklist of regions where an edit cannot operate.", - " - Useful for a \"freebuild\" worlds with few protected areas.", - " - May cause performance loss with large numbers of protected areas.", - " - Requires region-restrictions-options.allow-blacklists be true.", - " - Will still search for current allowed regions to limit the edit to.", - " - Any blacklist regions are likely to override any internal allowed regions." - }) - public boolean WORLDGUARD_REGION_BLACKLIST = false; - - } - - @Comment({ - "The \"default\" limit group affects those without a specific limit permission.", - "To grant someone different limits, copy the default limits group", - "and give it a different name (e.g. newbie). Then give the user the limit ", - "permission node with that limit name (e.g. fawe.limit.newbie )" - }) - @BlockName("default") // The name for the default block - public static class LIMITS extends ConfigBlock { - - @Comment("Max actions that can be run concurrently (i.e. commands)") - public int MAX_ACTIONS = 1; - @Comment("Max number of block changes (e.g. by `//set stone`).") - public long MAX_CHANGES = 50000000; - @Comment("Max number of blocks checked (e.g. `//count stone` which doesn't change blocks)") - public long MAX_CHECKS = 50000000; - @Comment("Number of times a change can fail (e.g. if the player can't access that region)") - public int MAX_FAILS = 50000000; - @Comment("Allowed brush iterations (e.g. `//brush smooth`)") - public int MAX_ITERATIONS = 1000; - @Comment("Max allowed entities (e.g. cows)") - public int MAX_ENTITIES = 1337; - @Comment({ - "Blockstates include Banner, Beacon, BrewingStand, Chest, CommandBlock, ", - "CreatureSpawner, Dispenser, Dropper, EndGateway, Furnace, Hopper, Jukebox, ", - "NoteBlock, Sign, Skull, Structure" - }) - public int MAX_BLOCKSTATES = 1337; - @Comment({ - "Maximum size of the player's history in Megabytes:", - " - History on disk or memory will be deleted", - }) - public int MAX_HISTORY_MB = -1; - @Comment("Maximum time in milliseconds //calc can execute") - public int MAX_EXPRESSION_MS = 50; - @Comment({ - "Cinematic block placement:", - " - Adds a delay to block placement (nanoseconds/block)", - " - Having an artificial delay will use more CPU/Memory", - }) - public int SPEED_REDUCTION = 0; - @Comment({ - "Place chunks instead of individual blocks:", - " - Disabling this will negatively impact performance", - " - Only disable this for compatibility or cinematic placement", - }) - public boolean FAST_PLACEMENT = true; - @Comment({ - "Should WorldEdit use inventory?", - "0 = No inventory usage (creative)", - "1 = Inventory for removing and placing (freebuild)", - "2 = Inventory for placing (survival)", - }) - public int INVENTORY_MODE = 0; - @Comment({ - "Should large edits require confirmation (>16384 chunks)", - }) - public boolean CONFIRM_LARGE = true; - @Comment({ - "If undo and redo commands should be restricted to allowed regions", - " - Prevents scenarios where players can delete/reset a region, and then continue to undo/redo on it" - }) - public boolean RESTRICT_HISTORY_TO_REGIONS = true; - @Comment({ - "List of nbt tags to strip from blocks, e.g. Items", - }) - public List STRIP_NBT = new ArrayList<>(); - @Comment({ - "If the disallowed blocks listed in config-legacy.yml should be disallowed in all edits,", - "not just where blocks patterns are used.", - " - Can prevent blocks being pasted from clipboards, etc.", - " - If fast-placement is disabled, this may cause edits to be slower." - }) - public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; - @Comment({ - "List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.", - "Where block properties are specified, any blockstate with the property will be disallowed (i.g. all directions", - "of a waterlogged fence). For blocking/remapping of all occurence of a property like waterlogged, see", - "remap-properties below.", - "Example block property blocking:", - " - \"minecraft:conduit[waterlogged=true]\"", - " - \"minecraft:piston[extended=false,facing=west]\"", - " - \"minecraft:wheat[age=7]\"" - }) - public List DISALLOWED_BLOCKS = Arrays.asList("minecraft:wheat", "minecraft:fire", "minecraft:redstone_wire"); - @Comment({ - "List of block properties that should be remapped if used in an edit. Entries should take the form", - "\"property_name[value1_old:value1_new,value2_old:value2_new]\". For example:", - " - \"waterlogged[true:false]\"", - " - \"age[7:4,6:4,5:4]\"", - " - \"extended[true:false]\"" - }) - public List REMAP_PROPERTIES = new ArrayList<>(); - - } - - public static class HISTORY { - - @Comment({ - "Should history be saved on disk:", - " - Frees up a lot of memory", - " - Persists restarts", - " - Unlimited undo", - " - Does not affect edit performance if `combine-stages`", - }) - public boolean USE_DISK = true; - @Comment({ - "Use a database to store disk storage summaries:", - " - Enables inspection and rollback", - " - Does not impact performance", - }) - public boolean USE_DATABASE = true; - @Comment({ - "Record history with dispatching:", - " - Much faster as it avoids duplicate block checks", - " - Slightly worse compression since dispatch order is different", - }) - public boolean COMBINE_STAGES = true; - @Comment({ - "Do not wait for a chunk's history to save before sending it", - " - Undo/redo commands will wait until the history has been written to disk before executing", - " - Requires combine-stages = true" - }) - public boolean SEND_BEFORE_HISTORY = true; - @Comment({ - "Higher compression reduces the size of history at the expense of CPU", - "0 = Uncompressed byte array (fastest)", - "1 = 1 pass fast compressor (default)", - "2 = 2 x fast", - "3 = 3 x fast", - "4 = 1 x medium, 1 x fast", - "5 = 1 x medium, 2 x fast", - "6 = 1 x medium, 3 x fast", - "7 = 1 x high, 1 x medium, 1 x fast", - "8 = 1 x high, 1 x medium, 2 x fast", - "9 = 1 x high, 1 x medium, 3 x fast (best compression)", - "NOTE: If using disk, do some compression (3+) as smaller files save faster", - " - levels over 6 require ZSTD 1.4.8+ to be installed to the system" - }) - public int COMPRESSION_LEVEL = 3; - @Comment({ - "The buffer size for compression:", - " - Larger = better ratio but uses more upfront memory", - " - Must be in the range [64, 33554432]", - }) - public int BUFFER_SIZE = 531441; - - - @Comment({ - "The maximum time in milliseconds to wait for a chunk to load for an edit.", - " (50ms = 1 server tick, 0 = Fastest).", - " The default value of 100 should be safe for most cases.", - "", - "Actions which require loaded chunks (e.g. copy) which do not load in time", - " will use the last chunk as filler, which may appear as bands of duplicated blocks.", - "Actions usually wait about 25-50ms for the chunk to load, more if the server is lagging.", - "A value of 100ms does not force it to wait 100ms if the chunk loads in 10ms.", - "", - "This value is a timeout in case a chunk is never going to load (for whatever odd reason).", - "If the action times out, the operation continues by using the previous chunk as filler,", - " and displaying an error message. In this case, either copy a smaller section,", - " or increase chunk-wait-ms.", - "A value of 0 is faster simply because it doesn't bother loading the chunks or waiting.", - }) - public int CHUNK_WAIT_MS = 1000; - @Comment("Delete history on disk after a number of days") - public int DELETE_AFTER_DAYS = 7; - @Comment("Delete history in memory on logout (does not effect disk)") - public boolean DELETE_ON_LOGOUT = true; - @Comment({ - "If history should be enabled by default for plugins using WorldEdit:", - " - It is faster to have disabled", - " - Use of the FAWE API will not be effected" - }) - public boolean ENABLE_FOR_CONSOLE = true; - @Comment({ - "Should redo information be stored:", - " - History is about 20% larger", - " - Enables use of /redo", - }) - public boolean STORE_REDO = true; - @Comment({ - "Assumes all edits are smaller than 4096x256x4096:", - " - Reduces history size by ~10%", - }) - public boolean SMALL_EDITS = false; - - } - - @Comment("This relates to how FAWE places chunks") - public static class QUEUE { - - @Comment({ - "This should equal the number of processors you have", - }) - public int PARALLEL_THREADS = Math.max(1, Runtime.getRuntime().availableProcessors()); - @Create - public static PROGRESS PROGRESS; - @Comment({ - "When doing edits that effect more than this many chunks:", - " - FAWE will start placing before all calculations are finished", - " - A larger value will use slightly less CPU time", - " - A smaller value will reduce memory usage", - " - A value too small may break some operations (deform?)", - " - Values smaller than the configurated parallel threads are not accepted" - - }) - public int TARGET_SIZE = 64; - @Comment({ - "Force FAWE to start placing chunks regardless of whether an edit is finished processing", - " - A larger value will use slightly less CPU time", - " - A smaller value will reduce memory usage", - " - A value too small may break some operations (deform?)" - }) - //TODO Find out where this was used and why the usage was removed - public int MAX_WAIT_MS = 1000; - - @Comment({ - "Increase or decrease queue intensity (ms) [-50,50]:", - " 0 = balance of performance / stability", - " -10 = Allocate 10ms less for chunk placement", - "Too high can cause lag spikes (you might be okay with this)", - "Too low will result in slow edits", - }) - public int EXTRA_TIME_MS = 0; - - @Comment({ - "Loading the right amount of chunks beforehand can speed up operations", - " - Low values may result in FAWE waiting on requests to the main thread", - " - Higher values use more memory and isn't noticeably faster", - " - A good (relatively) safe way to set this is", - " - Use 128 x GB of RAM / number of players expected to be using WE at the same time", - " - Paper and derivatives only. (requires delay-chunk-unloads-by to be set)." - }) - // Renamed from PRELOAD_CHUNK because it was set to 100000... something that lots of servers will now have which is - // wayyy too much... - public int PRELOAD_CHUNK_COUNT = 512; - - @Comment({ - "If pooling is enabled (reduces GC, higher memory usage)", - " - Enable to improve performance at the expense of memory", - }) - public boolean POOL = true; - - @Comment({ - "Discard edits which have been idle for a certain amount of time (ms)", - " - E.g. A plugin creates an EditSession but never does anything with it", - " - This only applies to plugins improperly using WorldEdit's legacy API" - }) - public int DISCARD_AFTER_MS = 60000; - - @Comment({ - "When using fastmode also do not bother to fix existing ticking blocks" - }) - public boolean NO_TICK_FASTMODE = true; - - public static class PROGRESS { - - @Comment({"Display constant titles about the progress of a user's edit", - " - false = disabled", - " - title = Display progress titles", - " - chat = Display progress in chat" - }) - public String DISPLAY = "false"; - @Comment("How often edit progress is displayed") - public int INTERVAL = 1; - @Comment("Delay sending progress in milliseconds (so quick edits don't spam)") - public int DELAY = 5000; - - } - - } - - @Comment({ - "Experimental options, use at your own risk", - " - UNSAFE = Can cause permanent damage to the server", - " - SAFE = Can be buggy but unlikely to cause any damage" - }) - public static class EXPERIMENTAL { - - @Comment({ - "[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)", - " - IMPROPER USE CAN CAUSE WORLD CORRUPTION!", - }) - public boolean ANVIL_QUEUE_MODE = false; - @Comment({ - "[SAFE] Dynamically increase the number of chunks rendered", - " - Requires Paper", - " - Set your server view distance to 1 (spigot.yml, server.properties)", - " - Based on tps and player movement", - " - Note: If entities become hidden, increase the server view distance to 3", - }) - public int DYNAMIC_CHUNK_RENDERING = -1; - @Comment({ - "Allows brushes to be persistent (default: true)", - }) - public boolean PERSISTENT_BRUSHES = true; - - @Comment({ - "[SAFE] Keep entities that are positioned in non-air blocks when editing an area", - "Might cause client-side FPS lag in some situations" - }) - public boolean KEEP_ENTITIES_IN_BLOCKS = false; - - @Comment({ - "Other experimental features" - }) - public boolean OTHER = false; - - @Comment({ - "Allow blocks placed by WorldEdit to tick. This could cause the big lags.", - "This has no effect on existing blocks one way or the other." - }) - public boolean ALLOW_TICK_PLACED = false; - - @Comment({ - "Force re-ticking of existing blocks not edited by FAWE.", - "This will increase time taken slightly." - }) - public boolean ALLOW_TICK_EXISTING = true; - - @Comment({ - "Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)", - "Set to -1 to disable" - }) - public int PER_PLAYER_FILE_SIZE_LIMIT = -1; - - @Comment({ - "Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)", - "Set to -1 to disable" - }) - public int PER_PLAYER_FILE_NUM_LIMIT = -1; - - } - - public static class PLOTSQUARED_INTEGRATION { - - @Comment({ - "Only disables/enables the components with PlotSquared v4.", - "For v6, see PlotSquared settings.yml" - }) - public boolean CLEAR = true; - public boolean COPY_AND_SWAP = true; - - } - - public static class WEB { - - @Comment({ - "The web interface for clipboards", - " - All schematics are anonymous and private", - " - Downloads can be deleted by the user", - " - Supports clipboard uploads, downloads and saves", - }) - public String URL = "https://schem.intellectualsites.com/fawe/"; - - } - - public static class EXTENT { - - @Comment({ - "Don't bug console when these plugins slow down WorldEdit operations", - " - You'll see a message in console or ingame if you need to change this option" - }) - public List ALLOWED_PLUGINS = new ArrayList<>(Collections.singleton(("com.example.ExamplePlugin"))); - @Comment("Should debug messages be sent when third party extents are used?") - public boolean DEBUG = true; - - } - - @Comment("Generic tick limiter (not necessarily WorldEdit related, but useful to stop abuse)") - public static class TICK_LIMITER { - - @Comment("Enable the limiter") - public boolean ENABLED = true; - @Comment("The interval in ticks") - public int INTERVAL = 20; - @Comment("Max falling blocks per interval (per chunk)") - public int FALLING = 64; - @Comment("Max physics per interval (excluding redstone)") - public int PHYSICS_MS = 10; - @Comment("Max item spawns per interval (per chunk)") - public int ITEMS = 256; - @Comment({ - "Whether fireworks can load chunks", - " - Fireworks usually travel vertically so do not load any chunks", - " - Horizontal fireworks can be hacked in to crash a server" - }) - public boolean FIREWORKS_LOAD_CHUNKS = false; - - } - - public static class CLIPBOARD { - - @Comment({ - "Store the clipboard on disk instead of memory", - " - Will be slightly slower", - " - Uses 2 bytes per block", - }) - public boolean USE_DISK = true; - @Comment({ - "Compress the clipboard to reduce the size:", - " - TODO: Buffered random access with compression is not implemented on disk yet", - " - 0 = No compression", - " - 1 = Fast compression", - " - 2-17 = Slower compression", - " - levels over 6 require ZSTD 1.4.8+ to be installed to the system" - }) - public int COMPRESSION_LEVEL = 1; - @Comment("Number of days to keep history on disk before deleting it") - public int DELETE_AFTER_DAYS = 1; - @Comment({ - "If a player's clipboard should be deleted upon logout" - }) - public boolean DELETE_ON_LOGOUT = false; - - } - - public static class LIGHTING { - - @Comment({ - "If packet sending should be delayed until relight is finished", - }) - public boolean DELAY_PACKET_SENDING = true; - public boolean ASYNC = true; - @Comment({ - "The relighting mode to use:", - " - 0 = None (Do no relighting)", - " - 1 = Optimal (Relight changed light sources and changed blocks)", - " - 2 = All (Slowly relight every blocks)", - }) - public int MODE = 1; - @Comment({"If existing lighting should be removed before relighting"}) - public boolean REMOVE_FIRST = true; - + /** + * Gets an instance of Settings. + * + * @return an instance of Settings + * @since 2.0.0 + */ + public static Settings settings() { + return INSTANCE; } public void reload(File file) { @@ -742,4 +247,501 @@ public class Settings extends Config { return limit; } + @Comment("Enable or disable core components") + public static final class ENABLED_COMPONENTS { + + public boolean COMMANDS = true; + @Comment({"Show additional information in console. It helps us at IntellectualSites to find out more about an issue.", + "Leave it off if you don't need it, it can spam your console."}) + public boolean DEBUG = false; + @Comment({"Whether or not FAWE should notify you on startup about new versions available."}) + public boolean UPDATE_NOTIFICATIONS = true; + + } + + @Comment("Paths for various directories") + public static final class PATHS { + + @Comment({ + "Put any minecraft or mod jars for FAWE to be aware of block textures", + }) + public String TEXTURES = "textures"; + public String HEIGHTMAP = "heightmap"; + public String HISTORY = "history"; + @Comment({ + "Multiple servers can use the same clipboards", + " - Use a shared directory or NFS/Samba" + }) + public String CLIPBOARD = "clipboard"; + @Comment("Each player has his or her own sub directory for schematics") + public boolean PER_PLAYER_SCHEMATICS = false; + + } + + @Comment("Region restriction settings") + public static final class REGION_RESTRICTIONS_OPTIONS { + + @Comment({ + "What type of users are allowed to WorldEdit in a region", + " - MEMBER = Players added to a region", + " - OWNER = Players who own the region" + }) + public String MODE = "MEMBER"; + @Comment({ + "Allow region blacklists.", + " - Currently only implemented for WorldGuard", + " - see region-restrictions-options.worldguard-region-blacklist" + }) + public boolean ALLOW_BLACKLISTS = false; + @Comment({ + "List of plugin mask managers that should be exclusive. Exclusive managers are not ", + "checked for edit restrictions if another manager already allowed an edit, and further ", + "managers are not checked if an exclusive manager allows an edit.", + " - May be useful to add PlotSquared if using both P2 and WorldGuard on a server", + " - Some custom-implementations in other plugins may override this setting" + }) + public List EXCLUSIVE_MANAGERS = new ArrayList<>(Collections.singleton(("ExamplePlugin"))); + @Comment({ + "If a worldguard-protected world should be considered as a region blacklist.", + " - This will create a blacklist of regions where an edit cannot operate.", + " - Useful for a \"freebuild\" worlds with few protected areas.", + " - May cause performance loss with large numbers of protected areas.", + " - Requires region-restrictions-options.allow-blacklists be true.", + " - Will still search for current allowed regions to limit the edit to.", + " - Any blacklist regions are likely to override any internal allowed regions." + }) + public boolean WORLDGUARD_REGION_BLACKLIST = false; + + } + + @Comment({ + "The \"default\" limit group affects those without a specific limit permission.", + "To grant someone different limits, copy the default limits group", + "and give it a different name (e.g. newbie). Then give the user the limit ", + "permission node with that limit name (e.g. fawe.limit.newbie )" + }) + @BlockName("default") // The name for the default block + public static class LIMITS extends ConfigBlock { + + @Comment("Max actions that can be run concurrently (i.e. commands)") + public int MAX_ACTIONS = 1; + @Comment("Max number of block changes (e.g. by `//set stone`).") + public long MAX_CHANGES = 50000000; + @Comment("Max number of blocks checked (e.g. `//count stone` which doesn't change blocks)") + public long MAX_CHECKS = 50000000; + @Comment("Number of times a change can fail (e.g. if the player can't access that region)") + public int MAX_FAILS = 50000000; + @Comment("Allowed brush iterations (e.g. `//brush smooth`)") + public int MAX_ITERATIONS = 1000; + @Comment("Max allowed entities (e.g. cows)") + public int MAX_ENTITIES = 1337; + @Comment({ + "Blockstates include Banner, Beacon, BrewingStand, Chest, CommandBlock, ", + "CreatureSpawner, Dispenser, Dropper, EndGateway, Furnace, Hopper, Jukebox, ", + "NoteBlock, Sign, Skull, Structure" + }) + public int MAX_BLOCKSTATES = 1337; + @Comment({ + "Maximum size of the player's history in Megabytes:", + " - History on disk or memory will be deleted", + }) + public int MAX_HISTORY_MB = -1; + @Comment("Maximum time in milliseconds //calc can execute") + public int MAX_EXPRESSION_MS = 50; + @Comment({ + "Cinematic block placement:", + " - Adds a delay to block placement (nanoseconds/block)", + " - Having an artificial delay will use more CPU/Memory", + }) + public int SPEED_REDUCTION = 0; + @Comment({ + "Place chunks instead of individual blocks:", + " - Disabling this will negatively impact performance", + " - Only disable this for compatibility or cinematic placement", + }) + public boolean FAST_PLACEMENT = true; + @Comment({ + "Should WorldEdit use inventory?", + "0 = No inventory usage (creative)", + "1 = Inventory for removing and placing (freebuild)", + "2 = Inventory for placing (survival)", + }) + public int INVENTORY_MODE = 0; + @Comment({ + "Should large edits require confirmation (>16384 chunks)", + }) + public boolean CONFIRM_LARGE = true; + @Comment({ + "If undo and redo commands should be restricted to allowed regions", + " - Prevents scenarios where players can delete/reset a region, and then continue to undo/redo on it" + }) + public boolean RESTRICT_HISTORY_TO_REGIONS = true; + @Comment({ + "List of nbt tags to strip from blocks, e.g. Items", + }) + public List STRIP_NBT = new ArrayList<>(); + @Comment({ + "If the disallowed blocks listed in worldedit-config.yml should be disallowed in all edits,", + "not just where blocks patterns are used.", + " - Can prevent blocks being pasted from clipboards, etc.", + " - If fast-placement is disabled, this may cause edits to be slower." + }) + public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; + @Comment({ + "List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.", + "Where block properties are specified, any blockstate with the property will be disallowed (i.g. all directions", + "of a waterlogged fence). For blocking/remapping of all occurence of a property like waterlogged, see", + "remap-properties below.", + "Example block property blocking:", + " - \"minecraft:conduit[waterlogged=true]\"", + " - \"minecraft:piston[extended=false,facing=west]\"", + " - \"minecraft:wheat[age=7]\"" + }) + public List DISALLOWED_BLOCKS = Arrays.asList("minecraft:wheat", "minecraft:fire", "minecraft:redstone_wire"); + @Comment({ + "List of block properties that should be remapped if used in an edit. Entries should take the form", + "\"property_name[value1_old:value1_new,value2_old:value2_new]\". For example:", + " - \"waterlogged[true:false]\"", + " - \"age[7:4,6:4,5:4]\"", + " - \"extended[true:false]\"" + }) + public List REMAP_PROPERTIES = new ArrayList<>(); + + } + + public static class HISTORY { + + @Comment({ + "Should history be saved on disk:", + " - Frees up a lot of memory", + " - Persists restarts", + " - Unlimited undo", + " - Does not affect edit performance if `combine-stages`", + }) + public boolean USE_DISK = true; + @Comment({ + "Use a database to store disk storage summaries:", + " - Enables inspection and rollback", + " - Does not impact performance", + }) + public boolean USE_DATABASE = true; + @Comment({ + "Record history with dispatching:", + " - Much faster as it avoids duplicate block checks", + " - Slightly worse compression since dispatch order is different", + }) + public boolean COMBINE_STAGES = true; + @Comment({ + "Do not wait for a chunk's history to save before sending it", + " - Undo/redo commands will wait until the history has been written to disk before executing", + " - Requires combine-stages = true" + }) + public boolean SEND_BEFORE_HISTORY = true; + @Comment({ + "Higher compression reduces the size of history at the expense of CPU", + "0 = Uncompressed byte array (fastest)", + "1 = 1 pass fast compressor (default)", + "2 = 2 x fast", + "3 = 3 x fast", + "4 = 1 x medium, 1 x fast", + "5 = 1 x medium, 2 x fast", + "6 = 1 x medium, 3 x fast", + "7 = 1 x high, 1 x medium, 1 x fast", + "8 = 1 x high, 1 x medium, 2 x fast", + "9 = 1 x high, 1 x medium, 3 x fast (best compression)", + "NOTE: If using disk, do some compression (3+) as smaller files save faster", + " - levels over 6 require ZSTD 1.4.8+ to be installed to the system" + }) + public int COMPRESSION_LEVEL = 3; + @Comment({ + "The buffer size for compression:", + " - Larger = better ratio but uses more upfront memory", + " - Must be in the range [64, 33554432]", + }) + public int BUFFER_SIZE = 531441; + + + @Comment({ + "The maximum time in milliseconds to wait for a chunk to load for an edit.", + " (50ms = 1 server tick, 0 = Fastest).", + " The default value of 100 should be safe for most cases.", + "", + "Actions which require loaded chunks (e.g. copy) which do not load in time", + " will use the last chunk as filler, which may appear as bands of duplicated blocks.", + "Actions usually wait about 25-50ms for the chunk to load, more if the server is lagging.", + "A value of 100ms does not force it to wait 100ms if the chunk loads in 10ms.", + "", + "This value is a timeout in case a chunk is never going to load (for whatever odd reason).", + "If the action times out, the operation continues by using the previous chunk as filler,", + " and displaying an error message. In this case, either copy a smaller section,", + " or increase chunk-wait-ms.", + "A value of 0 is faster simply because it doesn't bother loading the chunks or waiting.", + }) + public int CHUNK_WAIT_MS = 1000; + @Comment("Delete history on disk after a number of days") + public int DELETE_AFTER_DAYS = 7; + @Comment("Delete history in memory on logout (does not effect disk)") + public boolean DELETE_ON_LOGOUT = true; + @Comment({ + "If history should be enabled by default for plugins using WorldEdit:", + " - It is faster to have disabled", + " - Use of the FAWE API will not be effected" + }) + public boolean ENABLE_FOR_CONSOLE = true; + @Comment({ + "Should redo information be stored:", + " - History is about 20% larger", + " - Enables use of /redo", + }) + public boolean STORE_REDO = true; + @Comment({ + "Assumes all edits are smaller than 4096x256x4096:", + " - Reduces history size by ~10%", + }) + public boolean SMALL_EDITS = false; + + } + + @Comment("This relates to how FAWE places chunks") + public static class QUEUE { + + @Create + public static PROGRESS PROGRESS; + @Comment({ + "This should equal the number of processors you have", + }) + public int PARALLEL_THREADS = Math.max(1, Runtime.getRuntime().availableProcessors()); + @Comment({ + "When doing edits that effect more than this many chunks:", + " - FAWE will start placing before all calculations are finished", + " - A larger value will use slightly less CPU time", + " - A smaller value will reduce memory usage", + " - A value too small may break some operations (deform?)", + " - Values smaller than the configurated parallel threads are not accepted" + + }) + public int TARGET_SIZE = 64; + @Comment({ + "Force FAWE to start placing chunks regardless of whether an edit is finished processing", + " - A larger value will use slightly less CPU time", + " - A smaller value will reduce memory usage", + " - A value too small may break some operations (deform?)" + }) + //TODO Find out where this was used and why the usage was removed + public int MAX_WAIT_MS = 1000; + + @Comment({ + "Increase or decrease queue intensity (ms) [-50,50]:", + " 0 = balance of performance / stability", + " -10 = Allocate 10ms less for chunk placement", + "Too high can cause lag spikes (you might be okay with this)", + "Too low will result in slow edits", + }) + public int EXTRA_TIME_MS = 0; + + @Comment({ + "Loading the right amount of chunks beforehand can speed up operations", + " - Low values may result in FAWE waiting on requests to the main thread", + " - Higher values use more memory and isn't noticeably faster", + " - A good (relatively) safe way to set this is", + " - Use 128 x GB of RAM / number of players expected to be using WE at the same time", + " - Paper and derivatives only. (requires delay-chunk-unloads-by to be set)." + }) + // Renamed from PRELOAD_CHUNK because it was set to 100000... something that lots of servers will now have which is + // wayyy too much... + public int PRELOAD_CHUNK_COUNT = 512; + + @Comment({ + "If pooling is enabled (reduces GC, higher memory usage)", + " - Enable to improve performance at the expense of memory", + }) + public boolean POOL = true; + + @Comment({ + "Discard edits which have been idle for a certain amount of time (ms)", + " - E.g. A plugin creates an EditSession but never does anything with it", + " - This only applies to plugins improperly using WorldEdit's legacy API" + }) + public int DISCARD_AFTER_MS = 60000; + + @Comment({ + "When using fastmode also do not bother to fix existing ticking blocks" + }) + public boolean NO_TICK_FASTMODE = true; + + public static class PROGRESS { + + @Comment({"Display constant titles about the progress of a user's edit", + " - false = disabled", + " - title = Display progress titles", + " - chat = Display progress in chat" + }) + public String DISPLAY = "false"; + @Comment("How often edit progress is displayed") + public int INTERVAL = 1; + @Comment("Delay sending progress in milliseconds (so quick edits don't spam)") + public int DELAY = 5000; + + } + + } + + @Comment({ + "Experimental options, use at your own risk", + " - UNSAFE = Can cause permanent damage to the server", + " - SAFE = Can be buggy but unlikely to cause any damage" + }) + public static class EXPERIMENTAL { + + @Comment({ + "[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)", + " - IMPROPER USE CAN CAUSE WORLD CORRUPTION!", + }) + public boolean ANVIL_QUEUE_MODE = false; + @Comment({ + "[SAFE] Dynamically increase the number of chunks rendered", + " - Requires Paper", + " - Set your server view distance to 1 (spigot.yml, server.properties)", + " - Based on tps and player movement", + " - Note: If entities become hidden, increase the server view distance to 3", + }) + public int DYNAMIC_CHUNK_RENDERING = -1; + @Comment({ + "Allows brushes to be persistent (default: true)", + }) + public boolean PERSISTENT_BRUSHES = true; + + @Comment({ + "[SAFE] Keep entities that are positioned in non-air blocks when editing an area", + "Might cause client-side FPS lag in some situations" + }) + public boolean KEEP_ENTITIES_IN_BLOCKS = false; + + @Comment({ + "Other experimental features" + }) + public boolean OTHER = false; + + @Comment({ + "Allow blocks placed by WorldEdit to tick. This could cause the big lags.", + "This has no effect on existing blocks one way or the other." + }) + public boolean ALLOW_TICK_PLACED = false; + + @Comment({ + "Force re-ticking of existing blocks not edited by FAWE.", + "This will increase time taken slightly." + }) + public boolean ALLOW_TICK_EXISTING = true; + + @Comment({ + "Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)", + "Set to -1 to disable" + }) + public int PER_PLAYER_FILE_SIZE_LIMIT = -1; + + @Comment({ + "Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)", + "Set to -1 to disable" + }) + public int PER_PLAYER_FILE_NUM_LIMIT = -1; + + } + + public static class WEB { + + @Comment({ + "The web interface for clipboards", + " - All schematics are anonymous and private", + " - Downloads can be deleted by the user", + " - Supports clipboard uploads, downloads and saves", + }) + public String URL = "https://schem.intellectualsites.com/fawe/"; + + } + + public static class EXTENT { + + @Comment({ + "Don't bug console when these plugins slow down WorldEdit operations", + " - You'll see a message in console or ingame if you need to change this option" + }) + public List ALLOWED_PLUGINS = new ArrayList<>(Collections.singleton(("com.example.ExamplePlugin"))); + @Comment("Should debug messages be sent when third party extents are used?") + public boolean DEBUG = true; + + } + + /** + * @deprecated FAWE is not necessarily the tool you want to use to limit certain tick actions, e.g. fireworks or elytra flying. + * The code is untouched since the 1.12 era and there is no guarantee that it will work or will be maintained in the future. + */ + @Deprecated(since = "2.0.0") + @Comment("Generic tick limiter (not necessarily WorldEdit related, but useful to stop abuse)") + public static class TICK_LIMITER { + + @Comment("Enable the limiter") + public boolean ENABLED = true; + @Comment("The interval in ticks") + public int INTERVAL = 20; + @Comment("Max falling blocks per interval (per chunk)") + public int FALLING = 64; + @Comment("Max physics per interval (excluding redstone)") + public int PHYSICS_MS = 10; + @Comment("Max item spawns per interval (per chunk)") + public int ITEMS = 256; + @Comment({ + "Whether fireworks can load chunks", + " - Fireworks usually travel vertically so do not load any chunks", + " - Horizontal fireworks can be hacked in to crash a server" + }) + public boolean FIREWORKS_LOAD_CHUNKS = false; + + } + + public static class CLIPBOARD { + + @Comment({ + "Store the clipboard on disk instead of memory", + " - Will be slightly slower", + " - Uses 2 bytes per block", + }) + public boolean USE_DISK = true; + @Comment({ + "Compress the clipboard to reduce the size:", + " - TODO: Buffered random access with compression is not implemented on disk yet", + " - 0 = No compression", + " - 1 = Fast compression", + " - 2-17 = Slower compression", + " - levels over 6 require ZSTD 1.4.8+ to be installed to the system" + }) + public int COMPRESSION_LEVEL = 1; + @Comment("Number of days to keep history on disk before deleting it") + public int DELETE_AFTER_DAYS = 1; + @Comment({ + "If a player's clipboard should be deleted upon logout" + }) + public boolean DELETE_ON_LOGOUT = false; + + } + + public static class LIGHTING { + + @Comment({ + "If packet sending should be delayed until relight is finished", + }) + public boolean DELAY_PACKET_SENDING = true; + public boolean ASYNC = true; + @Comment({ + "The relighting mode to use:", + " - 0 = None (Do no relighting)", + " - 1 = Optimal (Relight changed light sources and changed blocks)", + " - 2 = All (Slowly relight every blocks)", + }) + public int MODE = 1; + @Comment({"If existing lighting should be removed before relighting"}) + public boolean REMOVE_FIRST = true; + + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java index d160c24c8..fd1263b11 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/DBHandler.java @@ -9,12 +9,28 @@ import java.util.concurrent.ConcurrentHashMap; public class DBHandler { - private static final Logger LOGGER = LogManagerCompat.getLogger(); - + /** + * @deprecated Use {@link #dbHandler()} instead. + */ + @Deprecated(forRemoval = true, since = "2.0.0") public static final DBHandler IMP = new DBHandler(); - + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static DBHandler INSTANCE; private final Map databases = new ConcurrentHashMap<>(8, 0.9f, 1); + /** + * Get an instance of the DBHandler. + * + * @return an instance of the DBHandler. + * @since 2.0.0 + */ + public static DBHandler dbHandler() { + if (INSTANCE == null) { + INSTANCE = new DBHandler(); + } + return INSTANCE; + } + public RollbackDatabase getDatabase(World world) { RollbackDatabase database = databases.get(world); if (database != null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index 209f93e3f..0e4843f2f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -11,7 +11,6 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.World; import org.apache.logging.log4j.Logger; -import org.intellij.lang.annotations.Language; import javax.annotation.Nonnull; import java.io.File; @@ -37,63 +36,22 @@ public class RollbackDatabase extends AsyncNotifyQueue { private final String prefix; private final File dbLocation; private final World world; - private Connection connection; - - @Language("SQLite") - private String createTable = "CREATE TABLE IF NOT EXISTS `{0}edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))"; - @Language("SQLite") - private String updateTable1 = "ALTER TABLE `{0}edits` ADD COLUMN `command` VARCHAR"; - @Language("SQLite") - private String updateTable2 = "alter table `{0}edits` add size int default 0 not null"; - @Language("SQLite") - private String insertEdit = "INSERT OR REPLACE INTO `{0}edits` (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)"; - @Language("SQLite") - private String purge = "DELETE FROM `{0}edits` WHERE `time`? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"; - @Language("SQLite") - private String getEditsUserAsc = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC"; - @Language("SQLite") - private String getEdits = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` DESC, `id` DESC"; - @Language("SQLite") - private String getEditsAsc = "SELECT * FROM `{0}edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` , `id` "; - @Language("SQLite") - private String getEditUser = "SELECT * FROM `{0}edits` WHERE `player`=? AND `id`=?"; - - @Language("SQLite") - private String deleteEditsUser = "DELETE FROM `{0}edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?"; - @Language("SQLite") - private String deleteEditUser = "DELETE FROM `{0}edits` WHERE `player`=? AND `id`=?"; - private final ConcurrentLinkedQueue historyChanges = new ConcurrentLinkedQueue<>(); + private Connection connection; RollbackDatabase(World world) throws SQLException, ClassNotFoundException { super((t, e) -> e.printStackTrace()); this.prefix = ""; this.world = world; this.dbLocation = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + "summary.db" + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + world.getName() + File.separator + "summary.db" ); connection = openConnection(); - // update vars - createTable = createTable.replace("{0}", prefix); - updateTable1 = updateTable1.replace("{0}", prefix); - updateTable2 = updateTable2.replace("{0}", prefix); - insertEdit = insertEdit.replace("{0}", prefix); - purge = purge.replace("{0}", prefix); - getEditsUser = getEditsUser.replace("{0}", prefix); - getEditsUserAsc = getEditsUserAsc.replace("{0}", prefix); - getEdits = getEdits.replace("{0}", prefix); - getEditsAsc = getEditsAsc.replace("{0}", prefix); - getEditUser = getEditUser.replace("{0}", prefix); - deleteEditsUser = deleteEditsUser.replace("{0}", prefix); - deleteEditUser = deleteEditUser.replace("{0}", prefix); - try { init().get(); - purge((int) TimeUnit.DAYS.toSeconds(Settings.IMP.HISTORY.DELETE_AFTER_DAYS)); + purge((int) TimeUnit.DAYS.toSeconds(Settings.settings().HISTORY.DELETE_AFTER_DAYS)); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -105,14 +63,17 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future init() { return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement(createTable)) { + try (PreparedStatement stmt = connection.prepareStatement("CREATE TABLE IF NOT EXISTS`" + this.prefix + + "edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1`" + + "INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1`" + + "INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) { stmt.executeUpdate(); } - try (PreparedStatement stmt = connection.prepareStatement(updateTable1)) { + try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD COLUMN `command` VARCHAR")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated - try (PreparedStatement stmt = connection.prepareStatement(updateTable2)) { + try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD SIZE INT DEFAULT 0 NOT NULL")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated @@ -122,7 +83,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future delete(UUID uuid, int id) { return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement(deleteEditUser)) { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); return stmt.executeUpdate(); @@ -132,7 +93,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future getEdit(@Nonnull UUID uuid, int id) { return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement(getEditUser)) { + try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM`" + this.prefix + + "edits` WHERE `player`=? AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); ResultSet result = stmt.executeQuery(); @@ -172,7 +134,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { long now = System.currentTimeMillis() / 1000; final int then = (int) (now - diff); return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement(purge)) { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `time` future = call(() -> { try { int count = 0; - String stmtStr = ascending ? uuid == null ? getEditsAsc : getEditsUserAsc : - uuid == null ? getEdits : getEditsUser; + String stmtStr = ascending ? uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND" + + " `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` , `id`" : + "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND" + + " `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC" : + uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? " + + "AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` DESC, `id` DESC" : + "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND" + + " `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC"; try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) { stmt.setInt(1, (int) (minTime / 1000)); stmt.setInt(2, pos1.getBlockX()); @@ -221,7 +189,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { } while (result.next()); } if (delete && uuid != null) { - try (PreparedStatement stmt = connection.prepareStatement(deleteEditsUser)) { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + + "edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) { stmt.setInt(1, (int) (minTime / 1000)); stmt.setInt(2, pos1.getBlockX()); stmt.setInt(3, pos2.getBlockX()); @@ -267,7 +236,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { RollbackOptimizedHistory[] copy = IntStream.range(0, size) .mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new); - try (PreparedStatement stmt = connection.prepareStatement(insertEdit)) { + try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "edits`" + + " (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)")) { // `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)" for (RollbackOptimizedHistory change : copy) { UUID uuid = change.getUUID(); @@ -314,8 +284,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { if (checkConnection()) { return connection; } - if (!Fawe.imp().getDirectory().exists()) { - Fawe.imp().getDirectory().mkdirs(); + if (!Fawe.platform().getDirectory().exists()) { + Fawe.platform().getDirectory().mkdirs(); } if (!dbLocation.exists()) { try { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java index 3f0ca3f0c..8eb221269 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java @@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.entity.EntityType; import javax.annotation.Nullable; @@ -11,26 +12,26 @@ import java.util.function.Supplier; public class LazyBaseEntity extends BaseEntity { - private Supplier saveTag; + private Supplier saveTag; - public LazyBaseEntity(EntityType type, Supplier saveTag) { + public LazyBaseEntity(EntityType type, Supplier saveTag) { super(type); this.saveTag = saveTag; } @Nullable @Override - public CompoundTag getNbtData() { - Supplier tmp = saveTag; + public CompoundBinaryTag getNbt() { + Supplier tmp = saveTag; if (tmp != null) { saveTag = null; if (Fawe.isMainThread()) { - setNbtData(tmp.get()); + setNbt(tmp.get()); } else { - setNbtData(TaskManager.IMP.sync(tmp)); + setNbt(TaskManager.taskManager().sync(tmp)); } } - return super.getNbtData(); + return super.getNbt(); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java index 478cbc46a..3c7ad1f4d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java @@ -166,7 +166,7 @@ public class ConsumeBindings extends Bindings { if (argument.length() > 16) { uuid = UUID.fromString(argument); } else { - uuid = Fawe.imp().getUUID(argument); + uuid = Fawe.platform().getUUID(argument); } if (uuid == null) { throw new InputParseException(Caption.of("fawe.error.player.not.found", TextComponent.of(argument))); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java index b296b5577..8a5b25058 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java @@ -68,7 +68,7 @@ public class ProvideBindings extends Bindings { @Binding public RollbackDatabase database(World world) { - return DBHandler.IMP.getDatabase(world); + return DBHandler.dbHandler().getDatabase(world); } @AllowedRegion(FaweMaskManager.MaskType.OWNER) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index b38a1b101..ac869b630 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -75,7 +75,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc throws WorldEditException { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return false; } @@ -86,7 +86,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public boolean setBiome(int x, int y, int z, BiomeType biome) { if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return false; } @@ -97,7 +97,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public BiomeType getBiome(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return null; } @@ -108,7 +108,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public BiomeType getBiomeType(int x, int y, int z) { if (!contains(x, z)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return null; } @@ -119,7 +119,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public BaseBlock getFullBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState().toBaseBlock(); } @@ -130,7 +130,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public BlockState getBlock(BlockVector3 position) { if (!contains(position)) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return BlockTypes.AIR.getDefaultState(); } @@ -142,7 +142,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc public Entity createEntity(Location location, BaseEntity entity) { if (!contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) { if (!limit.MAX_FAILS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.OUTSIDE_REGION); + WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MemoryCheckingExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MemoryCheckingExtent.java index a4398dc69..e2d215c56 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MemoryCheckingExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MemoryCheckingExtent.java @@ -29,7 +29,7 @@ public class MemoryCheckingExtent extends PassthroughExtent { this.actor.print(Caption.of("fawe.info.worldedit.oom.admin")); } } - WEManager.IMP.cancelEdit(this, FaweCache.LOW_MEMORY); + WEManager.weManager().cancelEdit(this, FaweCache.LOW_MEMORY); } return super.getExtent(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java index ab8c1d47b..9635497b2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ProcessedWEExtent.java @@ -37,7 +37,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { return null; } if (!limit.MAX_ENTITIES()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.MAX_ENTITIES); + WEManager.weManager().cancelEditSafe(this, FaweCache.MAX_ENTITIES); return null; } return super.createEntity(location, entity); @@ -46,7 +46,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public BlockState getBlock(int x, int y, int z) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.MAX_CHECKS); + WEManager.weManager().cancelEditSafe(this, FaweCache.MAX_CHECKS); return BlockTypes.AIR.getDefaultState(); } else { return extent.getBlock(x, y, z); @@ -56,7 +56,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public BaseBlock getFullBlock(BlockVector3 pos) { if (!limit.MAX_CHECKS()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.MAX_CHECKS); + WEManager.weManager().cancelEditSafe(this, FaweCache.MAX_CHECKS); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } else { return extent.getFullBlock(pos); @@ -80,18 +80,18 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { boolean hasNbt = block instanceof BaseBlock && block.hasNbtData(); if (hasNbt) { if (!limit.MAX_BLOCKSTATES()) { - WEManager.IMP.cancelEdit(this, FaweCache.MAX_TILES); + WEManager.weManager().cancelEdit(this, FaweCache.MAX_TILES); return false; } else { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, FaweCache.MAX_CHANGES); + WEManager.weManager().cancelEdit(this, FaweCache.MAX_CHANGES); return false; } return extent.setBlock(x, y, z, block); } } if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEdit(this, FaweCache.MAX_CHANGES); + WEManager.weManager().cancelEdit(this, FaweCache.MAX_CHANGES); return false; } else { return extent.setBlock(x, y, z, block); @@ -101,7 +101,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent { @Override public boolean setBiome(BlockVector3 position, BiomeType biome) { if (!limit.MAX_CHANGES()) { - WEManager.IMP.cancelEditSafe(this, FaweCache.MAX_CHANGES); + WEManager.weManager().cancelEditSafe(this, FaweCache.MAX_CHANGES); return false; } return super.setBiome(position, biome); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index 30f854b3d..efde68a56 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -72,8 +72,8 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable this( region.getDimensions(), MainUtil.getFile( - Fawe.get() != null ? Fawe.imp().getDirectory() : new File("."), - Settings.IMP.PATHS.CLIPBOARD + File.separator + uuid + ".bd" + Fawe.instance() != null ? Fawe.platform().getDirectory() : new File("."), + Settings.settings().PATHS.CLIPBOARD + File.separator + uuid + ".bd" ) ); setOffset(region.getMinimumPoint()); @@ -84,8 +84,8 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable this( dimensions, MainUtil.getFile( - Fawe.imp() != null ? Fawe.imp().getDirectory() : new File("."), - Settings.IMP.PATHS.CLIPBOARD + File.separator + UUID.randomUUID() + ".bd" + Fawe.platform() != null ? Fawe.platform().getDirectory() : new File("."), + Settings.settings().PATHS.CLIPBOARD + File.separator + UUID.randomUUID() + ".bd" ) ); } @@ -276,7 +276,7 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable int offsetZ = byteBuffer.getShort(20); region.shift(BlockVector3.at(offsetX, offsetY, offsetZ)); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, this); - clipboard.setOrigin(getOrigin()); + clipboard.setOrigin(getOrigin().add(offset)); return clipboard; } catch (Throwable e) { e.printStackTrace(); @@ -289,7 +289,7 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable int ox = byteBuffer.getShort(10); int oy = byteBuffer.getShort(12); int oz = byteBuffer.getShort(14); - return BlockVector3.at(ox, oy, oz); + return BlockVector3.at(ox, oy, oz).subtract(offset); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 8854027eb..6823acc97 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -54,7 +54,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard { private final int compressionLevel; public MemoryOptimizedClipboard(Region region) { - this(region, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL); + this(region, Settings.settings().CLIPBOARD.COMPRESSION_LEVEL); } public MemoryOptimizedClipboard(Region region, int compressionLevel) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java index 24b3a4daf..e46c58c0e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java @@ -39,12 +39,12 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { } public static ReadOnlyClipboard of(Extent extent, final Region region) { - Fawe.get().getQueueHandler().unCache(); + Fawe.instance().getQueueHandler().unCache(); return of(() -> extent, region); } public static ReadOnlyClipboard of(Extent extent, final Region region, boolean copyEntities, boolean copyBiomes) { - Fawe.get().getQueueHandler().unCache(); + Fawe.instance().getQueueHandler().unCache(); return of(() -> extent, region, copyEntities, copyBiomes); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java index 8847d0434..b3494e6d2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/SimpleClipboard.java @@ -7,10 +7,10 @@ import com.sk89q.worldedit.regions.Region; public abstract class SimpleClipboard implements Clipboard { + protected BlockVector3 offset; private final BlockVector3 size; private final int area; private final int volume; - private BlockVector3 offset; private BlockVector3 origin; SimpleClipboard(BlockVector3 dimensions, BlockVector3 offset) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java index 6d3a61359..87ca68044 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReader.java @@ -178,7 +178,7 @@ public class FastSchematicReader extends NBTSchematicReader { try { state = BlockState.get(palettePart); } catch (InputParseException ignored) { - LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + LOGGER.warn("Invalid BlockState in palette: {}. Block will be replaced with air.", palettePart); state = BlockTypes.AIR.getDefaultState(); } int index = (int) entry.getValue(); @@ -327,7 +327,7 @@ public class FastSchematicReader extends NBTSchematicReader { // tiles if (tiles != null && !tiles.isEmpty()) { for (Map tileRaw : tiles) { - CompoundTag tile = FaweCache.IMP.asTag(tileRaw); + CompoundTag tile = FaweCache.INSTANCE.asTag(tileRaw); int[] pos = tile.getIntArray("Pos"); int x; @@ -372,7 +372,7 @@ public class FastSchematicReader extends NBTSchematicReader { // entities if (entities != null && !entities.isEmpty()) { for (Map entRaw : entities) { - Map value = new HashMap<>(FaweCache.IMP.asTag(entRaw).getValue()); + Map value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue()); StringTag id = (StringTag) value.get("Id"); if (id == null) { id = (StringTag) value.get("id"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java index f5861e4d1..696dd3ef5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java @@ -123,7 +123,7 @@ public class FastSchematicWriter implements ClipboardWriter { out1.writeNamedTag("WEOffsetX", offset.getBlockX()); out1.writeNamedTag("WEOffsetY", offset.getBlockY()); out1.writeNamedTag("WEOffsetZ", offset.getBlockZ()); - out1.writeNamedTag("FAWEVersion", Fawe.get().getVersion().build); + out1.writeNamedTag("FAWEVersion", Fawe.instance().getVersion().build); }); ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index 600ccf50b..79d5f8186 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -165,7 +165,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (width > WARN_SIZE || height > WARN_SIZE || length > WARN_SIZE) { LOGGER.info("A structure longer than 32 is unsupported by minecraft (but probably still works)"); } - Map structure = FaweCache.IMP.asMap("version", 1, "author", owner); + Map structure = FaweCache.INSTANCE.asMap("version", 1, "author", owner); // ignored: version / owner Int2ObjectArrayMap indexes = new Int2ObjectArrayMap<>(); // Size @@ -217,10 +217,10 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { point.getY() - min.getY(), point.getZ() - min.getZ() ); if (!block.hasNbtData()) { - blocks.add(FaweCache.IMP.asMap("state", index, "pos", pos)); + blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); } else { blocks.add( - FaweCache.IMP.asMap("state", index, "pos", pos, "nbt", block.getNbtData())); + FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", block.getNbtData())); } } } @@ -240,14 +240,14 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { // Replace rotation data nbtMap.put("Rotation", writeRotation(entity.getLocation())); nbtMap.put("id", new StringTag(state.getType().getId())); - Map entityMap = FaweCache.IMP.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt); + Map entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt); entities.add(entityMap); } } if (!entities.isEmpty()) { structure.put("entities", entities); } - out.writeNamedTag("", FaweCache.IMP.asTag(structure)); + out.writeNamedTag("", FaweCache.INSTANCE.asTag(structure)); close(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java index b4812e2e8..92be10e66 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/PNGWriter.java @@ -26,7 +26,7 @@ public class PNGWriter implements ClipboardWriter { public PNGWriter(OutputStream out) throws IOException { this.out = ImageIO.createImageOutputStream(out); - this.tu = Fawe.get().getCachedTextureUtil(false, 0, 100); + this.tu = Fawe.instance().getCachedTextureUtil(false, 0, 100); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/visualizer/SchemVis.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/visualizer/SchemVis.java index b1a393c51..7debe40dd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/visualizer/SchemVis.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/visualizer/SchemVis.java @@ -203,7 +203,7 @@ // */ // private void clean() { // if (chunks.size() > 225) { -// TaskManager.IMP.sync(() -> { +// TaskManager.taskManager().sync(() -> { // if (chunks.size() > 225) { // synchronized (SchemVis.this) { // Location pos = player.toWorldEditPlayer().getLocation(); @@ -233,7 +233,7 @@ // * @param chunkZ // */ // private void send(IQueueExtent packetQueue, int chunkX, int chunkZ) { -// TaskManager.IMP.getPublicForkJoinPool().submit(() -> { +// TaskManager.taskManager().getPublicForkJoinPool().submit(() -> { // try { // int OX = chunkOffset.getBlockX(); // int OZ = chunkOffset.getBlockZ(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java index 9cefe420f..1a2e4705e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java @@ -71,7 +71,7 @@ public class CharFilterBlock extends ChunkFilterBlock { maxLayer = this.get.getMaxSectionPosition(); this.layer = layer; if (!iget.hasSection(layer)) { - getArr = FaweCache.IMP.EMPTY_CHAR_4096; + getArr = FaweCache.INSTANCE.EMPTY_CHAR_4096; } else { getArr = iget.load(layer); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/ExtentBatchProcessorHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/ExtentBatchProcessorHolder.java index b83ea2c4b..20dced74e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/ExtentBatchProcessorHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/ExtentBatchProcessorHolder.java @@ -21,7 +21,7 @@ public abstract class ExtentBatchProcessorHolder extends BatchProcessorHolder im @Override public Extent enableHistory(AbstractChangeSet changeSet) { - if (Settings.IMP.HISTORY.SEND_BEFORE_HISTORY) { + if (Settings.settings().HISTORY.SEND_BEFORE_HISTORY) { return this.addPostProcessor(changeSet); } else { return this.addProcessor(changeSet); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java index 55ed8aab7..ca463f911 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/MultiBatchProcessor.java @@ -34,7 +34,7 @@ public class MultiBatchProcessor implements IBatchProcessor { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final LoadingCache, Map> classToThreadIdToFilter = - FaweCache.IMP.createCache((Supplier>) ConcurrentHashMap::new); + FaweCache.INSTANCE.createCache((Supplier>) ConcurrentHashMap::new); // Array for lazy avoidance of concurrent modification exceptions and needless overcomplication of code (synchronisation is // not very important) private boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; @@ -157,7 +157,7 @@ public class MultiBatchProcessor implements IBatchProcessor { lastException = hash; exceptionCount = 0; LOGGER.catching(e); - } else if (exceptionCount < Settings.IMP.QUEUE.PARALLEL_THREADS) { + } else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) { exceptionCount++; LOGGER.warn(message); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java index c42d51677..efdf79846 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java @@ -62,7 +62,7 @@ public class HeightmapProcessor implements IBatchProcessor { continue; } char[] setSection = hasSectionSet ? set.loadIfPresent(layer) : null; - if (setSection == null || Arrays.equals(setSection, FaweCache.IMP.EMPTY_CHAR_4096) || + if (setSection == null || Arrays.equals(setSection, FaweCache.INSTANCE.EMPTY_CHAR_4096) || Arrays.equals(setSection, AIR_LAYER)) { hasSectionSet = false; } @@ -86,7 +86,7 @@ public class HeightmapProcessor implements IBatchProcessor { } else if (getSection == null) { getSection = get.load(layer); // skip empty layer - if (Arrays.equals(getSection, FaweCache.IMP.EMPTY_CHAR_4096) + if (Arrays.equals(getSection, FaweCache.INSTANCE.EMPTY_CHAR_4096) || Arrays.equals(getSection, AIR_LAYER)) { hasSectionGet = false; if (!hasSectionSet) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java index 7be725bc8..ef8b73f21 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/NMSRelighter.java @@ -77,7 +77,7 @@ public class NMSRelighter implements Relighter { this.concurrentLightQueue = new ConcurrentHashMap<>(12); this.maxY = queue.getMaxY(); this.minY = queue.getMinY(); - this.relightMode = relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE); + this.relightMode = relightMode != null ? relightMode : RelightMode.valueOf(Settings.settings().LIGHTING.MODE); this.lightingLock = new ReentrantLock(); } @@ -911,11 +911,11 @@ public class NMSRelighter implements Relighter { chunk.setBitMask(bitMask); iter.remove(); } - if (Settings.IMP.LIGHTING.ASYNC) { + if (Settings.settings().LIGHTING.ASYNC) { queue.flush(); finished.set(true); } else { - TaskManager.IMP.sync(new RunnableVal<>() { + TaskManager.taskManager().sync(new RunnableVal<>() { @Override public void run(Object value) { queue.flush(); @@ -943,16 +943,16 @@ public class NMSRelighter implements Relighter { ChunkHolder chunk = (ChunkHolder) queue.getOrCreateChunk(x, z); chunk.setBitMask(bitMask); chunk.flushLightToGet(); - Fawe.imp().getPlatformAdapter().sendChunk(chunk.getOrCreateGet(), bitMask, true); + Fawe.platform().getPlatformAdapter().sendChunk(chunk.getOrCreateGet(), bitMask, true); iter.remove(); } finished.set(true); } }; - if (Settings.IMP.LIGHTING.ASYNC) { + if (Settings.settings().LIGHTING.ASYNC) { runnable.run(); } else { - TaskManager.IMP.sync(runnable); + TaskManager.taskManager().sync(runnable); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelightProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelightProcessor.java index c9b71beb1..8ac56c0f1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelightProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/lighting/RelightProcessor.java @@ -25,9 +25,9 @@ public class RelightProcessor implements IBatchProcessor { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - if (Settings.IMP.LIGHTING.MODE == 2) { + if (Settings.settings().LIGHTING.MODE == 2) { relighter.addChunk(chunk.getX(), chunk.getZ(), null, chunk.getBitMask()); - } else if (Settings.IMP.LIGHTING.MODE == 1) { + } else if (Settings.settings().LIGHTING.MODE == 1) { byte[] fix = new byte[get.getSectionCount()]; boolean relight = false; for (int i = get.getMaxSectionPosition(); i >= get.getMinSectionPosition(); i--) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java index 6cc3eef7f..28bfa0a4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/CavesGen.java @@ -1,7 +1,6 @@ package com.fastasyncworldedit.core.function.generator; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.world.block.BlockID; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector2; @@ -237,11 +236,8 @@ public class CavesGen extends GenBase { BlockState material = chunk.getBlock(bx + local_x, local_y, bz + local_z); BlockState materialAbove = chunk.getBlock(bx + local_x, local_y + 1, bz + local_z); BlockType blockType = material.getBlockType(); - switch (blockType.getInternalId()) { - case BlockID.MYCELIUM: - case BlockID.GRASS: - grassFound = true; - + switch (blockType.getId()) { + case "minecraft:mycelium", "minecraft:grass_block" -> grassFound = true; } if (this.isSuitableBlock(material, materialAbove)) { if (local_y - 1 < 10) { @@ -281,17 +277,10 @@ public class CavesGen extends GenBase { } protected boolean isSuitableBlock(BlockStateHolder material, BlockStateHolder materialAbove) { - switch (material.getBlockType().getInternalId()) { - case BlockID.AIR: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - case BlockID.WATER: - case BlockID.LAVA: - case BlockID.BEDROCK: - return false; - default: - return true; - } + return switch (material.getBlockType().getId()) { + case "minecraft:air", "minecraft:cave_air", "minecraft:void_air", "minecraft:water", "minecraft:lava", "minecraft:bedrock" -> false; + default -> true; + }; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java index 84cc42d45..399d96663 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java @@ -32,7 +32,7 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter } actionTime = tmp; this.pattern = parent; - this.timer = Fawe.get().getTimer(); + this.timer = Fawe.instance().getTimer(); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java index 1e307c560..7d0bfe76e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/DiskStorageHistory.java @@ -75,8 +75,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet { private void init(UUID uuid, String worldName) { final File folder = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + worldName + File.separator + uuid + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + worldName + File.separator + uuid ); final int max = NEXT_INDEX.computeIfAbsent(worldName, _worldName -> new ConcurrentHashMap<>()) @@ -111,8 +111,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet { this.uuid = uuid; this.index = i; File folder = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + getWorld().getName() + File.separator + uuid + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + getWorld().getName() + File.separator + uuid ); initFiles(folder); } @@ -120,8 +120,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet { @Override public void delete() { deleteFiles(); - if (Settings.IMP.HISTORY.USE_DATABASE) { - RollbackDatabase db = DBHandler.IMP.getDatabase(getWorld()); + if (Settings.settings().HISTORY.USE_DATABASE) { + RollbackDatabase db = DBHandler.dbHandler().getDatabase(getWorld()); db.delete(uuid, index); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/MemoryOptimizedHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/MemoryOptimizedHistory.java index 32ac92b48..9e575c2a7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/MemoryOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/MemoryOptimizedHistory.java @@ -149,7 +149,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { } synchronized (this) { setOrigin(x, z); - idsStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + idsStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); idsStreamZip = getCompressedOS(idsStream); writeHeader(idsStreamZip, x, y, z); return idsStreamZip; @@ -170,7 +170,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { return biomeStreamZip; } synchronized (this) { - biomeStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + biomeStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); biomeStreamZip = getCompressedOS(biomeStream); return biomeStreamZip; } @@ -191,7 +191,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { if (entCStreamZip != null) { return entCStreamZip; } - entCStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + entCStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); return entCStreamZip = new NBTOutputStream(getCompressedOS(entCStream)); } @@ -200,7 +200,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { if (entRStreamZip != null) { return entRStreamZip; } - entRStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + entRStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); return entRStreamZip = new NBTOutputStream(getCompressedOS(entRStream)); } @@ -209,7 +209,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { if (tileCStreamZip != null) { return tileCStreamZip; } - tileCStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + tileCStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); return tileCStreamZip = new NBTOutputStream(getCompressedOS(tileCStream)); } @@ -218,7 +218,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { if (tileRStreamZip != null) { return tileRStreamZip; } - tileRStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + tileRStream = new FastByteArrayOutputStream(Settings.settings().HISTORY.BUFFER_SIZE); return tileRStreamZip = new NBTOutputStream(getCompressedOS(tileRStream)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java index ee2862cdf..6e7e4068b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/RollbackOptimizedHistory.java @@ -99,7 +99,7 @@ public class RollbackOptimizedHistory extends DiskStorageHistory { public void close() throws IOException { super.close(); // Save to DB - RollbackDatabase db = DBHandler.IMP.getDatabase(getWorld()); + RollbackDatabase db = DBHandler.dbHandler().getDatabase(getWorld()); if (db != null) { db.logEdit(this); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 0e9413f8a..cceb1b7cd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.TaskManager; -import com.fastasyncworldedit.core.world.block.BlockID; import com.google.common.util.concurrent.Futures; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; @@ -31,6 +30,7 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypesCache; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -65,7 +65,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { return; } waitingAsync.incrementAndGet(); - TaskManager.IMP.async(() -> { + TaskManager.taskManager().async(() -> { waitingAsync.decrementAndGet(); synchronized (waitingAsync) { waitingAsync.notifyAll(); @@ -169,7 +169,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { char[] blocksGet; char[] tmp = get.load(layer); if (tmp == null) { - blocksGet = FaweCache.IMP.EMPTY_CHAR_4096; + blocksGet = FaweCache.INSTANCE.EMPTY_CHAR_4096; } else { System.arraycopy(tmp, 0, (blocksGet = new char[4096]), 0, 4096); } @@ -186,8 +186,8 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { for (int x = 0; x < 16; x++, index++) { int xx = bx + x; int from = blocksGet[index]; - if (from == 0) { - from = BlockID.AIR; + if (from == BlockTypesCache.ReservedIDs.__RESERVED__) { + from = BlockTypesCache.ReservedIDs.AIR; } final int combinedFrom = from; final int combinedTo = blocksSet[index]; @@ -199,22 +199,23 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } } - BiomeType[] biomes = set.getBiomes(); + BiomeType[][] biomes = set.getBiomes(); if (biomes != null) { - int index = 0; for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { if (!set.hasBiomes(layer)) { continue; } + BiomeType[] biomeSection = biomes[layer - set.getMinSectionPosition()]; + int index = 0; int yy = layer << 4; - for (int y = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType newBiome = biomes[index]; + for (int y = 0; y < 16; y+= 4) { + for (int z = 0; z < 16; z+= 4) { + for (int x = 0; x < 16; x+= 4, index++) { + BiomeType newBiome = biomeSection[index]; if (newBiome != null) { - BiomeType oldBiome = get.getBiomeType(x, y, z); + BiomeType oldBiome = get.getBiomeType(x, yy + y, z); if (oldBiome != newBiome) { - addBiomeChange(bx + (x << 2), yy + (y << 2), bz + (z << 2), oldBiome, newBiome); + addBiomeChange(bx + x, yy + y, bz + z, oldBiome, newBiome); } } } @@ -379,7 +380,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { wrappedTask.run(); return Futures.immediateCancelledFuture(); } else { - return Fawe.get().getQueueHandler().submit(wrappedTask); + return Fawe.instance().getQueueHandler().submit(wrappedTask); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index c780297cc..77869a7ce 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -43,7 +43,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { protected FaweStreamPositionDelegate posDel; public FaweStreamChangeSet(World world) { - this(world, Settings.IMP.HISTORY.COMPRESSION_LEVEL, Settings.IMP.HISTORY.STORE_REDO, Settings.IMP.HISTORY.SMALL_EDITS); + this(world, Settings.settings().HISTORY.COMPRESSION_LEVEL, Settings.settings().HISTORY.STORE_REDO, Settings.settings().HISTORY.SMALL_EDITS); } public FaweStreamChangeSet(World world, int compression, boolean storeRedo, boolean smallLoc) { @@ -764,7 +764,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } try (FaweInputStream fis = getBlockIS()) { if (!shallow) { - int amount = (Settings.IMP.HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9; + int amount = (Settings.settings().HISTORY.BUFFER_SIZE - HEADER_SIZE) / 9; MutableFullBlockChange change = new MutableFullBlockChange(null, 0, false); for (int i = 0; i < amount; i++) { int x = posDel.readX(fis) + ox; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java index 2dad4500d..baa20163f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableBlockVector3.java @@ -14,7 +14,7 @@ public class MutableBlockVector3 extends BlockVector3 { } public static MutableBlockVector3 get(int x, int y, int z) { - return FaweCache.IMP.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z); + return FaweCache.INSTANCE.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z); } public MutableBlockVector3() { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java index a23b910ce..22d85d38a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/MutableVector3.java @@ -27,11 +27,11 @@ public class MutableVector3 extends Vector3 { } public static MutableVector3 get(int x, int y, int z) { - return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z); + return FaweCache.INSTANCE.MUTABLE_VECTOR3.get().setComponents(x, y, z); } public static MutableVector3 get(double x, double y, double z) { - return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z); + return FaweCache.INSTANCE.MUTABLE_VECTOR3.get().setComponents(x, y, z); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index 2b4eb84f1..ff6842c0a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -3,13 +3,13 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; -import com.fastasyncworldedit.core.world.block.BlockID; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.registry.BlockRegistry; import javax.annotation.Nullable; @@ -116,11 +116,9 @@ public interface IBlocks extends Trimable { for (int i = 0; i < ids.length; i++) { char ordinal = ids[i]; switch (ordinal) { - case BlockID.__RESERVED__: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - ids[i] = BlockID.AIR; - case BlockID.AIR: + case BlockTypesCache.ReservedIDs.__RESERVED__, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR: + ids[i] = BlockTypesCache.ReservedIDs.AIR; + case BlockTypesCache.ReservedIDs.AIR: continue; default: nonEmpty++; @@ -130,9 +128,9 @@ public interface IBlocks extends Trimable { sectionWriter.writeShort(nonEmpty); // non empty FaweCache.Palette palette; if (stretched) { - palette = FaweCache.IMP.toPalette(0, ids); + palette = FaweCache.INSTANCE.toPalette(0, ids); } else { - palette = FaweCache.IMP.toPaletteUnstretched(0, ids); + palette = FaweCache.INSTANCE.toPaletteUnstretched(0, ids); } sectionWriter.writeByte(palette.bitsPerEntry); // bits per block @@ -140,17 +138,13 @@ public interface IBlocks extends Trimable { for (int i = 0; i < palette.paletteToBlockLength; i++) { int ordinal = palette.paletteToBlock[i]; switch (ordinal) { - case BlockID.__RESERVED__: - case BlockID.CAVE_AIR: - case BlockID.VOID_AIR: - case BlockID.AIR: - sectionWriter.write(0); - break; - default: + case BlockTypesCache.ReservedIDs.__RESERVED__, BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, + BlockTypesCache.ReservedIDs.VOID_AIR -> sectionWriter.write(0); + default -> { BlockState state = BlockState.getFromOrdinal(ordinal); int mcId = registry.getInternalBlockStateId(state).getAsInt(); sectionWriter.writeVarInt(mcId); - break; + } } } sectionWriter.writeVarInt(palette.blockStatesLength); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java index 318e8ebeb..79aed9f23 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java @@ -64,7 +64,7 @@ public interface IChunkSet extends IBlocks, OutputExtent { * * @return Array of biomes set */ - BiomeType[] getBiomes(); + BiomeType[][] getBiomes(); default boolean hasBiomes() { return getBiomes() != null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/Flood.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/Flood.java index 142e79d67..6d431c1b6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/Flood.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/Flood.java @@ -45,7 +45,7 @@ public class Flood { } public synchronized void run(World world) { - QueueHandler queueHandler = Fawe.get().getQueueHandler(); + QueueHandler queueHandler = Fawe.instance().getQueueHandler(); IQueueExtent fq = queueHandler.getQueue(world); while (!chunkQueues.isEmpty()) { long firstKey = chunkQueues.firstLongKey(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index 58671f0ba..89c3b549f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -99,7 +99,7 @@ public class ParallelQueueExtent extends PassthroughExtent { final Iterator chunksIter = chunks.iterator(); // Get a pool, to operate on the chunks in parallel - final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); + final int size = Math.min(chunks.size(), Settings.settings().QUEUE.PARALLEL_THREADS); if (size <= 1 && chunksIter.hasNext()) { BlockVector2 pos = chunksIter.next(); getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); @@ -147,7 +147,7 @@ public class ParallelQueueExtent extends PassthroughExtent { lastException = hash; exceptionCount = 0; LOGGER.catching(e); - } else if (exceptionCount < Settings.IMP.QUEUE.PARALLEL_THREADS) { + } else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) { exceptionCount++; LOGGER.warn(message); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java index 83e9da4f9..cd731d10b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/QueueHandler.java @@ -41,7 +41,7 @@ public abstract class QueueHandler implements Trimable, Runnable { private final ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(); private final ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(); - private final ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor(); + private final ThreadPoolExecutor blockingExecutor = FaweCache.INSTANCE.newBlockingExecutor(); private final ConcurrentLinkedQueue syncTasks = new ConcurrentLinkedQueue<>(); private final ConcurrentLinkedQueue syncWhenFree = new ConcurrentLinkedQueue<>(); @@ -56,7 +56,7 @@ public abstract class QueueHandler implements Trimable, Runnable { private double targetTPS = 18; public QueueHandler() { - TaskManager.IMP.repeat(this, 1); + TaskManager.taskManager().repeat(this, 1); } @Override @@ -87,14 +87,14 @@ public abstract class QueueHandler implements Trimable, Runnable { private long getAllocate() { long now = System.currentTimeMillis(); - targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0); + targetTPS = 18 - Math.max(Settings.settings().QUEUE.EXTRA_TIME_MS * 0.05, 0); long diff = 50 + this.last - (this.last = now); long absDiff = Math.abs(diff); if (diff == 0) { allocate = Math.min(50, allocate + 1); } else if (diff < 0) { allocate = Math.max(5, allocate + diff); - } else if (!Fawe.get().getTimer().isAbove(targetTPS)) { + } else if (!Fawe.instance().getTimer().isAbove(targetTPS)) { allocate = Math.max(5, allocate - 1); } return allocate - absDiff; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java index 8f1c1c489..97513aa69 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java @@ -250,7 +250,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen } } - return (V) Fawe.get().getQueueHandler().submit(chunk); + return (V) Fawe.instance().getQueueHandler().submit(chunk); } @Override @@ -266,7 +266,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (aggressive) { pollSubmissions(0, aggressive); } else { - pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, aggressive); + pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, aggressive); } } synchronized (this) { @@ -312,8 +312,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen // If queueing is enabled AND either of the following // - memory is low & queue size > num threads + 8 // - queue size > target size and primary queue has less than num threads submissions - if (enabledQueue && ((lowMem && size > Settings.IMP.QUEUE.PARALLEL_THREADS + 8) || (size > Settings.IMP.QUEUE.TARGET_SIZE && Fawe - .get() + if (enabledQueue && ((lowMem && size > Settings.settings().QUEUE.PARALLEL_THREADS + 8) || (size > Settings.settings().QUEUE.TARGET_SIZE && Fawe + .instance() .getQueueHandler() .isUnderutilized()))) { chunk = chunks.removeFirst(); @@ -321,9 +321,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (future != null && !future.isDone()) { final int targetSize; if (lowMem) { - targetSize = Settings.IMP.QUEUE.PARALLEL_THREADS + 8; + targetSize = Settings.settings().QUEUE.PARALLEL_THREADS + 8; } else { - targetSize = Settings.IMP.QUEUE.TARGET_SIZE; + targetSize = Settings.settings().QUEUE.TARGET_SIZE; } pollSubmissions(targetSize, lowMem); submissions.add(future); @@ -361,10 +361,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen * @param region region of chunks */ public void preload(Region region) { - if (Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) { + if (Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT > 1) { int loadCount = 0; for (BlockVector2 from : region.getChunks()) { - if (loadCount >= Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT) { + if (loadCount >= Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT) { break; } loadCount++; @@ -409,7 +409,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen lastException = hash; exceptionCount = 0; LOGGER.catching(e); - } else if (exceptionCount < Settings.IMP.QUEUE.PARALLEL_THREADS) { + } else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) { exceptionCount++; LOGGER.warn(message); } @@ -449,7 +449,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen lastException = hash; exceptionCount = 0; LOGGER.catching(e); - } else if (exceptionCount < Settings.IMP.QUEUE.PARALLEL_THREADS) { + } else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) { exceptionCount++; LOGGER.warn(message); } @@ -464,7 +464,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen for (IQueueChunk chunk : chunks.values()) { final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { - pollSubmissions(Settings.IMP.QUEUE.PARALLEL_THREADS, true); + pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, true); submissions.add(future); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java index efa635626..3e01ecc40 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java @@ -9,6 +9,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypesCache; import javax.annotation.Nullable; import java.util.Arrays; @@ -59,7 +60,7 @@ public class BitSetBlocks implements IChunkSet { for (int y = 0, index = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++, index++) { - if (data[index] != 0) { + if (data[index] != BlockTypesCache.ReservedIDs.__RESERVED__) { row.set(null, x, by + y, z, minSectionPosition, maxSectionPosition); } } @@ -124,7 +125,7 @@ public class BitSetBlocks implements IChunkSet { @Override public char[] load(int layer) { layer -= minSectionPosition; - char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get(); + char[] arr = FaweCache.INSTANCE.SECTION_BITS_TO_CHAR.get(); MemBlockSet.IRow nullRowY = row.getRow(layer); if (nullRowY instanceof MemBlockSet.RowY) { char value = blockState.getOrdinalChar(); @@ -161,7 +162,7 @@ public class BitSetBlocks implements IChunkSet { } @Override - public BiomeType[] getBiomes() { + public BiomeType[][] getBiomes() { return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 882cbe682..39735679d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -134,7 +134,7 @@ public abstract class CharBlocks implements IBlocks { return new char[4096]; } for (int i = 0; i < 4096; i++) { - data[i] = 0; + data[i] = defaultOrdinal(); } return data; } @@ -188,11 +188,16 @@ public abstract class CharBlocks implements IBlocks { int layer = y >> 4; final int index = (y & 15) << 8 | z << 4 | x; if (layer > maxSectionPosition || layer < minSectionPosition) { - return 0; + return defaultOrdinal(); } return get(layer, index); } + /** + * Default char value to be used when "updating"/resetting data arrays + */ + protected abstract char defaultOrdinal(); + // Not synchronized as it refers to a synchronized method and includes nothing that requires synchronization public void set(int x, int y, int z, char value) { final int layer = y >> 4; @@ -201,7 +206,7 @@ public abstract class CharBlocks implements IBlocks { set(layer, index, value); } catch (ArrayIndexOutOfBoundsException exception) { LOGGER.error("Tried setting block at coordinates (" + x + "," + y + "," + z + ")"); - assert Fawe.imp() != null; + assert Fawe.platform() != null; LOGGER.error("Layer variable was = {}", layer, exception); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java index fad00ca6b..2299e9b4d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharGetBlocks.java @@ -37,10 +37,15 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { if (data == null) { data = new char[4096]; } - Arrays.fill(data, (char) 1); + Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); return data; } + @Override + protected char defaultOrdinal() { + return BlockTypesCache.ReservedIDs.AIR; + } + @Override public synchronized boolean trim(boolean aggressive, int layer) { layer -= minSectionPosition; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java index 9b59a4915..1b0451195 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java @@ -11,6 +11,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypesCache; import java.util.Arrays; import java.util.Collections; @@ -23,17 +24,17 @@ import java.util.stream.IntStream; public class CharSetBlocks extends CharBlocks implements IChunkSet { - private static final Pool POOL = FaweCache.IMP.registerPool( + private static final Pool POOL = FaweCache.INSTANCE.registerPool( CharSetBlocks.class, CharSetBlocks::new, - Settings.IMP.QUEUE.POOL + Settings.settings().QUEUE.POOL ); public static CharSetBlocks newInstance() { return POOL.poll(); } - public BiomeType[] biomes; + public BiomeType[][] biomes; public char[][] light; public char[][] skyLight; public BlockVector3ChunkMap tiles; @@ -54,17 +55,19 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { } @Override - public BiomeType[] getBiomes() { + public BiomeType[][] getBiomes() { return biomes; } @Override public BiomeType getBiomeType(int x, int y, int z) { + int layer; if (biomes == null || (y >> 4) < minSectionPosition || (y >> 4) > maxSectionPosition) { return null; + } else if (biomes[(layer = (y >> 4) - minSectionPosition)] == null) { + return null; } - y -= minSectionPosition << 4; - return biomes[(y >> 2) << 4 | (z >> 2) << 2 | x >> 2]; + return biomes[layer][(y & 15) >> 2 | (z >> 2) << 2 | x >> 2]; } @Override @@ -95,11 +98,14 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { updateSectionIndexRange(y >> 4); - y -= minSectionPosition << 4; + int layer = (y >> 4) - minSectionPosition; if (biomes == null) { - biomes = new BiomeType[64 * sectionCount]; + biomes = new BiomeType[sectionCount][]; + biomes[layer] = new BiomeType[64]; + } else if (biomes[layer] == null) { + biomes[layer] = new BiomeType[64]; } - biomes[(y >> 2) << 4 | (z >> 2) << 2 | x >> 2] = biome; + biomes[layer][(y & 12) << 2 | (z & 12) | (x & 12) >> 2] = biome; return true; } @@ -312,7 +318,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { if (layer < 0 || layer >= sections.length) { return false; } - return biomes != null; + return biomes != null && biomes[layer] != null; } @Override @@ -321,6 +327,11 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { return super.load(layer); } + @Override + protected char defaultOrdinal() { + return BlockTypesCache.ReservedIDs.__RESERVED__; + } + // Checks and updates the various section arrays against the new layer index private void updateSectionIndexRange(int layer) { if (layer >= minSectionPosition && layer <= maxSectionPosition) { @@ -344,7 +355,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { sectionLocks = tmpSectionLocks; minSectionPosition = layer; if (biomes != null) { - BiomeType[] tmpBiomes = new BiomeType[sectionCount * 64]; + BiomeType[][] tmpBiomes = new BiomeType[sectionCount][64]; System.arraycopy(biomes, 0, tmpBiomes, 64 * diff, biomes.length); biomes = tmpBiomes; } @@ -376,7 +387,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { sectionLocks = tmpSectionLocks; maxSectionPosition = layer; if (biomes != null) { - BiomeType[] tmpBiomes = new BiomeType[sectionCount * 64]; + BiomeType[][] tmpBiomes = new BiomeType[sectionCount][64]; System.arraycopy(biomes, 0, tmpBiomes, 0, biomes.length); biomes = tmpBiomes; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java index eea966ebc..8f7b8007c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java @@ -124,7 +124,7 @@ public final class NullChunkGet implements IChunkGet { @Nonnull public char[] load(int layer) { - return FaweCache.IMP.EMPTY_CHAR_4096; + return FaweCache.INSTANCE.EMPTY_CHAR_4096; } @Nullable diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 7a7706f87..5634dd1f5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -32,10 +32,10 @@ import java.util.concurrent.Future; @SuppressWarnings("rawtypes") public class ChunkHolder> implements IQueueChunk { - private static final Pool POOL = FaweCache.IMP.registerPool( + private static final Pool POOL = FaweCache.INSTANCE.registerPool( ChunkHolder.class, ChunkHolder::new, - Settings.IMP.QUEUE.POOL + Settings.settings().QUEUE.POOL ); public static ChunkHolder newInstance() { @@ -96,7 +96,7 @@ public class ChunkHolder> implements IQueueChunk { } @Override - public BiomeType[] getBiomes() { + public BiomeType[][] getBiomes() { // Uses set as this method is only used to retrieve biomes that have been set to the extent/chunk. return delegate.set(this).getBiomes(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java index 9b6d72b95..99757a513 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java @@ -122,7 +122,7 @@ public final class NullChunk implements IQueueChunk { } @Nullable - public BiomeType[] getBiomes() { + public BiomeType[][] getBiomes() { return null; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/packet/ChunkPacket.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/packet/ChunkPacket.java index 9df1a8f9f..7f8195bbc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/packet/ChunkPacket.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/packet/ChunkPacket.java @@ -64,8 +64,8 @@ public class ChunkPacket implements Function, Supplier { synchronized (this) { if (sectionBytes == null) { IBlocks tmpChunk = getChunk(); - byte[] buf = FaweCache.IMP.BYTE_BUFFER_8192.get(); - sectionBytes = tmpChunk.toByteArray(buf, tmpChunk.getBitMask(), this.full, Fawe.imp().isChunksStretched()); + byte[] buf = FaweCache.INSTANCE.BYTE_BUFFER_8192.get(); + sectionBytes = tmpChunk.toByteArray(buf, tmpChunk.getBitMask(), this.full, Fawe.platform().isChunksStretched()); } tmp = sectionBytes; } @@ -85,14 +85,14 @@ public class ChunkPacket implements Function, Supplier { @Override @Deprecated public byte[] get() { - return apply(FaweCache.IMP.BYTE_BUFFER_8192.get()); + return apply(FaweCache.INSTANCE.BYTE_BUFFER_8192.get()); } public CompoundTag getHeightMap() { HashMap map = new HashMap<>(); map.put("MOTION_BLOCKING", new long[36]); // TODO - return FaweCache.IMP.asTag(map); + return FaweCache.INSTANCE.asTag(map); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java index 43d18f3a7..29e82790d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/preloader/AsyncPreloader.java @@ -31,7 +31,7 @@ public class AsyncPreloader implements Preloader, Runnable { public AsyncPreloader() { this.update = new ConcurrentHashMap<>(); - TaskManager.IMP.laterAsync(this, 1); + TaskManager.taskManager().laterAsync(this, 1); } @Override @@ -77,7 +77,7 @@ public class AsyncPreloader implements Preloader, Runnable { existing.setKey(world); existing.setValue(ImmutableSet.copyOf(Iterables.limit( region.getChunks(), - Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT + Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT ))); } synchronized (update) { @@ -89,12 +89,12 @@ public class AsyncPreloader implements Preloader, Runnable { @Override public void run() { - FaweTimer timer = Fawe.get().getTimer(); + FaweTimer timer = Fawe.instance().getTimer(); if (cancelled.get()) { return; } if (update.isEmpty()) { - TaskManager.IMP.laterAsync(this, 1); + TaskManager.taskManager().laterAsync(this, 1); return; } Iterator>>> plrIter = update.entrySet().iterator(); @@ -118,7 +118,7 @@ public class AsyncPreloader implements Preloader, Runnable { if (cancelled.get()) { return; } - TaskManager.IMP.laterAsync(this, 20); + TaskManager.taskManager().laterAsync(this, 20); } private void queueLoad(World world, BlockVector2 chunk) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java index 62f54e49b..60c6e6be9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java @@ -23,41 +23,13 @@ public abstract class FaweMaskManager { return this.key; } - /** - * Get a {@link FaweMask} for the given player and {@link MaskType} - * - * @deprecated Use {@link #getMask(Player, MaskType, boolean)} - */ - @Deprecated(forRemoval = true) - public FaweMask getMask(final Player player, MaskType type) { - return getMask(player, type, true); - } - /** * Get a {@link FaweMask} for the given player and {@link MaskType}. If isWhitelist is false, will return a "blacklist" mask. */ - public FaweMask getMask(final Player player, MaskType type, boolean isWhitelist) { - return getMask(player, type); - } - - /** - * @deprecated Not used internally - */ - @Deprecated(forRemoval = true) - public boolean isValid(FaweMask mask) { - return true; - } - - /** - * @deprecated Not used internally - */ - @Deprecated(forRemoval = true) - public RegionFilter getFilter(String world) { - return null; - } + public abstract FaweMask getMask(final Player player, MaskType type, boolean isWhitelist); public boolean isExclusive() { - return Settings.IMP.REGION_RESTRICTIONS_OPTIONS.EXCLUSIVE_MANAGERS.contains(this.key); + return Settings.settings().REGION_RESTRICTIONS_OPTIONS.EXCLUSIVE_MANAGERS.contains(this.key); } public enum MaskType { @@ -67,7 +39,7 @@ public abstract class FaweMaskManager { public static MaskType getDefaultMaskType() { try { return MaskType - .valueOf(Settings.IMP.REGION_RESTRICTIONS_OPTIONS.MODE.toUpperCase(Locale.ROOT)); + .valueOf(Settings.settings().REGION_RESTRICTIONS_OPTIONS.MODE.toUpperCase(Locale.ROOT)); } catch (Exception ignored) { return MEMBER; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java index a5d38deee..e382583aa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/RegionWrapper.java @@ -1,5 +1,7 @@ package com.fastasyncworldedit.core.regions; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; @@ -27,7 +29,13 @@ public class RegionWrapper extends CuboidRegion { */ @Deprecated public RegionWrapper(final int minX, final int maxX, final int minZ, final int maxZ) { - this(minX, maxX, 0, 255, minZ, maxZ); + this(minX, + maxX, + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(), + minZ, + maxZ + ); } public RegionWrapper(final int minX, final int maxX, final int minY, final int maxY, final int minZ, final int maxZ) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java index 8145c4514..5c7cdc34b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/registry/state/PropertyKey.java @@ -18,8 +18,13 @@ public class PropertyKey implements Comparable { // constants public static final PropertyKey AGE = getOrCreate("age"); public static final PropertyKey ATTACHED = getOrCreate("attached"); + public static final PropertyKey ATTACHMENT = getOrCreate("attachement"); public static final PropertyKey AXIS = getOrCreate("axis"); + public static final PropertyKey BERRIES = getOrCreate("berries"); public static final PropertyKey BITES = getOrCreate("bites"); + public static final PropertyKey BOTTOM = getOrCreate("bottom"); + public static final PropertyKey CANDLES = getOrCreate("candles"); + public static final PropertyKey CHARGES = getOrCreate("charges"); public static final PropertyKey CONDITIONAL = getOrCreate("conditional"); public static final PropertyKey DELAY = getOrCreate("delay"); public static final PropertyKey DISARMED = getOrCreate("disarmed"); @@ -33,17 +38,22 @@ public class PropertyKey implements Comparable { public static final PropertyKey EYE = getOrCreate("eye"); public static final PropertyKey FACE = getOrCreate("face"); public static final PropertyKey FACING = getOrCreate("facing"); + public static final PropertyKey FALLING = getOrCreate("falling"); public static final PropertyKey HALF = getOrCreate("half"); + public static final PropertyKey HANGING = getOrCreate("hanging"); + public static final PropertyKey HAS_BOOK = getOrCreate("has_book"); public static final PropertyKey HAS_BOTTLE_0 = getOrCreate("has_bottle_0"); public static final PropertyKey HAS_BOTTLE_1 = getOrCreate("has_bottle_1"); public static final PropertyKey HAS_BOTTLE_2 = getOrCreate("has_bottle_2"); public static final PropertyKey HAS_RECORD = getOrCreate("has_record"); public static final PropertyKey HATCH = getOrCreate("hatch"); public static final PropertyKey HINGE = getOrCreate("hinge"); - public static final PropertyKey IN_WALL = getOrCreate("in_wall"); + public static final PropertyKey HONEY_LEVEL = getOrCreate("honey_level"); public static final PropertyKey INSTRUMENT = getOrCreate("instrument"); public static final PropertyKey INVERTED = getOrCreate("inverted"); + public static final PropertyKey IN_WALL = getOrCreate("in_wall"); public static final PropertyKey LAYERS = getOrCreate("layers"); + public static final PropertyKey LEAVES = getOrCreate("leaves"); public static final PropertyKey LEVEL = getOrCreate("level"); public static final PropertyKey LIT = getOrCreate("lit"); public static final PropertyKey LOCKED = getOrCreate("locked"); @@ -53,29 +63,30 @@ public class PropertyKey implements Comparable { public static final PropertyKey NOTE = getOrCreate("note"); public static final PropertyKey OCCUPIED = getOrCreate("occupied"); public static final PropertyKey OPEN = getOrCreate("open"); + public static final PropertyKey ORIENTATION = getOrCreate("orientation"); public static final PropertyKey PART = getOrCreate("part"); public static final PropertyKey PERSISTENT = getOrCreate("persistent"); public static final PropertyKey PICKLES = getOrCreate("pickles"); public static final PropertyKey POWER = getOrCreate("power"); public static final PropertyKey POWERED = getOrCreate("powered"); public static final PropertyKey ROTATION = getOrCreate("rotation"); + public static final PropertyKey SCULK_SENSOR_PHASE = getOrCreate("sculk_sensor_phase"); public static final PropertyKey SHAPE = getOrCreate("shape"); public static final PropertyKey SHORT = getOrCreate("short"); + public static final PropertyKey SIGNAL_FIRE = getOrCreate("signal_fire"); public static final PropertyKey SNOWY = getOrCreate("snowy"); public static final PropertyKey SOUTH = getOrCreate("south"); public static final PropertyKey STAGE = getOrCreate("stage"); + public static final PropertyKey TILT = getOrCreate("tilt"); + public static final PropertyKey THICKNESS = getOrCreate("thickness"); public static final PropertyKey TRIGGERED = getOrCreate("triggered"); public static final PropertyKey TYPE = getOrCreate("type"); + public static final PropertyKey UNSTABLE = getOrCreate("unstable"); public static final PropertyKey UP = getOrCreate("up"); + public static final PropertyKey VERTICAL_DIRECTION = getOrCreate("vertical_direction"); + public static final PropertyKey VINE_END = getOrCreate("vine_end"); public static final PropertyKey WATERLOGGED = getOrCreate("waterlogged"); public static final PropertyKey WEST = getOrCreate("west"); - public static final PropertyKey UNSTABLE = getOrCreate("unstable"); - public static final PropertyKey LEAVES = getOrCreate("leaves"); - public static final PropertyKey ATTACHMENT = getOrCreate("attachement"); - public static final PropertyKey SIGNAL_FIRE = getOrCreate("signal_fire"); - public static final PropertyKey HANGING = getOrCreate("hanging"); - public static final PropertyKey HAS_BOOK = getOrCreate("has_book"); - public static final PropertyKey BOTTOM = getOrCreate("bottom"); private final String name; private final int id; @@ -90,10 +101,6 @@ public class PropertyKey implements Comparable { return keyList.size(); } - public final String getName() { - return this.name; - } - public static PropertyKey getByName(CharSequence name) { return keys.get(name); } @@ -116,6 +123,10 @@ public class PropertyKey implements Comparable { }); } + public final String getName() { + return this.name; + } + public int getId() { return id; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java deleted file mode 100644 index e99c3a162..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java +++ /dev/null @@ -1,498 +0,0 @@ -package com.fastasyncworldedit.core.util; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.FaweRegionExtent; -import com.fastasyncworldedit.core.extent.HistoryExtent; -import com.fastasyncworldedit.core.extent.LimitExtent; -import com.fastasyncworldedit.core.extent.MultiRegionExtent; -import com.fastasyncworldedit.core.extent.NullExtent; -import com.fastasyncworldedit.core.extent.SingleRegionExtent; -import com.fastasyncworldedit.core.extent.SlowExtent; -import com.fastasyncworldedit.core.extent.StripNBTExtent; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightmapProcessor; -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightProcessor; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.history.DiskStorageHistory; -import com.fastasyncworldedit.core.history.MemoryOptimizedHistory; -import com.fastasyncworldedit.core.history.RollbackOptimizedHistory; -import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; -import com.fastasyncworldedit.core.history.changeset.BlockBagChangeSet; -import com.fastasyncworldedit.core.history.changeset.NullChangeSet; -import com.fastasyncworldedit.core.limit.FaweLimit; -import com.fastasyncworldedit.core.queue.IQueueChunk; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; -import com.fastasyncworldedit.core.regions.RegionWrapper; -import com.fastasyncworldedit.core.wrappers.WorldWrapper; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.event.extent.EditSessionEvent; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.inventory.BlockBag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Identifiable; -import com.sk89q.worldedit.util.eventbus.EventBus; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.world.World; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.Nullable; - -import javax.annotation.Nonnull; -import java.util.Locale; -import java.util.UUID; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * @deprecated Being replaced by {@link com.sk89q.worldedit.EditSessionBuilder}. See https://worldedit.enginehub.org/en/latest/api/concepts/edit-sessions/ - */ -@Deprecated(forRemoval = true) -public class EditSessionBuilder { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - @Nonnull - private World world; - private Player player; - private FaweLimit limit; - private AbstractChangeSet changeSet; - private Region[] allowedRegions; - private Boolean fastmode; - private Boolean checkMemory; - private Boolean combineStages; - @Nonnull - private EventBus eventBus = WorldEdit.getInstance().getEventBus(); - private BlockBag blockBag; - private EditSessionEvent event; - private String command; - private RelightMode relightMode; - private Relighter relighter; - private Boolean wnaMode; - private AbstractChangeSet changeTask; - private Extent bypassHistory; - private Extent bypassAll; - private Extent extent; - private boolean compiled; - private boolean wrapped; - - /** - * An EditSession builder
- * - Unset values will revert to their default
- *
- * player: The player doing the edit (defaults to to null)
- * limit: Block/Entity/Action limit (defaults to unlimited)
- * changeSet: Stores changes (defaults to config.yml value)
- * allowedRegions: Allowed editable regions (defaults to player's allowed regions, or everywhere)
- * fastmode: bypasses history (defaults to player fastmode or config.yml console history)
- * checkMemory: If low memory checks are enabled (defaults to player's fastmode or true)
- * combineStages: If history is combined with dispatching - * - * @param world A world must be provided for all EditSession(s) - */ - public EditSessionBuilder(World world) { - checkNotNull(world); - this.world = world; - } - - public EditSessionBuilder player(@Nullable Player player) { - this.player = player; - return setDirty(); - } - - public EditSessionBuilder limit(@Nullable FaweLimit limit) { - this.limit = limit; - return setDirty(); - } - - public EditSessionBuilder limitUnlimited() { - return limit(FaweLimit.MAX.copy()); - } - - public EditSessionBuilder limitUnprocessed(@Nonnull Player player) { - checkNotNull(player); - limitUnlimited(); - FaweLimit tmp = player.getLimit(); - limit.INVENTORY_MODE = tmp.INVENTORY_MODE; - return setDirty(); - } - - public EditSessionBuilder changeSet(@Nullable AbstractChangeSet changeSet) { - this.changeSet = changeSet; - return setDirty(); - } - - public EditSessionBuilder changeSetNull() { - return changeSet(new NullChangeSet(world)); - } - - public EditSessionBuilder world(@Nonnull World world) { - checkNotNull(world); - this.world = world; - return setDirty(); - } - - public EditSessionBuilder command(String command) { - this.command = command; - return this; - } - - public EditSessionBuilder changeSet(boolean disk, @Nullable UUID uuid, int compression) { - if (disk) { - if (Settings.IMP.HISTORY.USE_DATABASE) { - this.changeSet = new RollbackOptimizedHistory(world, uuid); - } else { - this.changeSet = new DiskStorageHistory(world, uuid); - } - } else { - this.changeSet = new MemoryOptimizedHistory(world); - } - return setDirty(); - } - - public EditSessionBuilder allowedRegions(@Nullable Region[] allowedRegions) { - this.allowedRegions = allowedRegions; - return setDirty(); - } - - @Deprecated - public EditSessionBuilder allowedRegions(@Nullable RegionWrapper[] allowedRegions) { - this.allowedRegions = allowedRegions; - return setDirty(); - } - - public EditSessionBuilder allowedRegions(@Nullable RegionWrapper allowedRegion) { - this.allowedRegions = allowedRegion == null ? null : allowedRegion.toArray(); - return setDirty(); - } - - public EditSessionBuilder allowedRegionsEverywhere() { - return allowedRegions(new Region[]{RegionWrapper.GLOBAL()}); - } - - @Deprecated - public EditSessionBuilder autoQueue(@Nullable Boolean autoQueue) { - return this; - } - - public EditSessionBuilder fastmode(@Nullable Boolean fastmode) { - this.fastmode = fastmode; - return setDirty(); - } - - public EditSessionBuilder relightMode(@Nullable RelightMode relightMode) { - this.relightMode = relightMode; - return setDirty(); - } - - public EditSessionBuilder checkMemory(@Nullable Boolean checkMemory) { - this.checkMemory = checkMemory; - return setDirty(); - } - - public EditSessionBuilder combineStages(@Nullable Boolean combineStages) { - this.combineStages = combineStages; - return setDirty(); - } - - public EditSessionBuilder blockBag(@Nullable BlockBag blockBag) { - this.blockBag = blockBag; - return setDirty(); - } - - public EditSessionBuilder eventBus(@Nonnull EventBus eventBus) { - this.eventBus = eventBus; - return setDirty(); - } - - public EditSessionBuilder event(@Nullable EditSessionEvent event) { - this.event = event; - return setDirty(); - } - - public EditSessionBuilder forceWNA() { - this.wnaMode = true; - return setDirty(); - } - - private EditSessionBuilder setDirty() { - compiled = false; - return this; - } - - private Extent wrapExtent( - final Extent extent, - final EventBus eventBus, - EditSessionEvent event, - final EditSession.Stage stage - ) { - event = event.clone(stage); - event.setExtent(extent); - eventBus.post(event); - if (event.isCancelled()) { - return new NullExtent(extent, FaweCache.MANUAL); - } - final Extent toReturn = event.getExtent(); - if (toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { - return new NullExtent(toReturn, FaweCache.MANUAL); - } - if (toReturn != extent) { - String className = toReturn.getClass().getName().toLowerCase(Locale.ROOT); - for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { - if (className.contains(allowed.toLowerCase(Locale.ROOT))) { - this.wrapped = true; - return toReturn; - } - } - if (Settings.IMP.EXTENT.DEBUG) { - if (event.getActor() != null) { - event.getActor().printDebug(TextComponent.of("Potentially unsafe extent blocked: " + toReturn - .getClass() - .getName())); - event.getActor().print(TextComponent.of( - "- For area restrictions and block logging, it is recommended that third party plugins use the FAWE" + - " API")); - event.getActor().print(TextComponent.of("- Add the following line to the `allowed-plugins` list in the " + - "FAWE config.yml to let FAWE recognize the extent:")); - event.getActor().print(toReturn.getClass().getName()); - } else { - LOGGER.warn("Potentially unsafe extent blocked: " + toReturn.getClass().getName()); - LOGGER.warn( - " - For area restrictions and block logging, it is recommended that third party plugins use the FAWE API"); - LOGGER.warn( - " - Add the following classpath to the `allowed-plugins` list in the FAWE config.yml to let FAWE " + - "recognize the extent:"); - LOGGER.warn(toReturn.getClass().getName()); - } - } - } - return extent; - } - - public EditSessionBuilder compile() { - if (compiled) { - return this; - } - - compiled = true; - wrapped = false; - if (event == null) { - event = new EditSessionEvent(world, player, -1, null); - } - if (player == null && event.getActor() != null) { - player = (Player) event.getActor(); - } - if (limit == null) { - if (player == null) { - limit = FaweLimit.MAX; - } else { - limit = player.getLimit(); - } - } - if (fastmode == null) { - if (player == null) { - fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; - } else { - fastmode = player.getSession().hasFastMode(); - } - } - if (checkMemory == null) { - checkMemory = player != null && !this.fastmode; - } - if (checkMemory) { - if (MemUtil.isMemoryLimitedSlow()) { - if (Permission.hasPermission(player, "worldedit.fast")) { - player.print(Caption.of("fawe.info.worldedit.oom.admin")); - } - throw FaweCache.LOW_MEMORY; - } - } -// this.originalLimit = limit; - this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; - this.limit = limit.copy(); - - if (extent == null) { - IQueueExtent queue = null; - World unwrapped = WorldWrapper.unwrap(world); - boolean placeChunks = (this.fastmode || this.limit.FAST_PLACEMENT) && (wnaMode == null || !wnaMode); - - if (placeChunks) { - wnaMode = false; - if (unwrapped instanceof IQueueExtent) { - extent = queue = (IQueueExtent) unwrapped; - } else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) { - ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, fastmode); - queue = parallel.getExtent(); - extent = parallel; - } else { - extent = queue = Fawe.get().getQueueHandler().getQueue(world); - } - } else { - wnaMode = true; - extent = world; - } - if (combineStages == null) { - combineStages = - // If it's enabled in the settings - Settings.IMP.HISTORY.COMBINE_STAGES - // If fast placement is disabled, it's slower to perform a copy on each chunk - && this.limit.FAST_PLACEMENT - // If the edit uses items from the inventory we can't use a delayed task - && this.blockBag == null; - } - extent = this.bypassAll = wrapExtent(extent, eventBus, event, EditSession.Stage.BEFORE_CHANGE); - this.bypassHistory = this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER); - if (!this.fastmode || changeSet != null) { - if (changeSet == null) { - if (Settings.IMP.HISTORY.USE_DISK) { - UUID uuid = player == null ? Identifiable.CONSOLE : player.getUniqueId(); - if (Settings.IMP.HISTORY.USE_DATABASE) { - changeSet = new RollbackOptimizedHistory(world, uuid); - } else { - changeSet = new DiskStorageHistory(world, uuid); - } -// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) { -// changeSet = new CPUOptimizedChangeSet(world); - } else { - if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) { - //TODO add CPUOptimizedChangeSet - } - changeSet = new MemoryOptimizedHistory(world); - } - } - if (this.limit.SPEED_REDUCTION > 0) { - this.extent = this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); - } - if (command != null && changeSet instanceof RollbackOptimizedHistory) { - ((RollbackOptimizedHistory) changeSet).setCommand(this.command); - } - if (!(changeSet instanceof NullChangeSet)) { - if (this.blockBag != null) { - //TODO implement block bag as IBatchProcessor - changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); - } - if (combineStages) { - changeTask = changeSet; - this.extent = extent.enableHistory(changeSet); - } else { - this.extent = new HistoryExtent(extent, changeSet); -// if (this.blockBag != null) { -// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); -// } - } - } - } - if (allowedRegions == null) { - if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions")) { - allowedRegions = player.getAllowedRegions(); - } - } - FaweRegionExtent regionExtent = null; - if (allowedRegions != null) { - if (allowedRegions.length == 0) { - regionExtent = new NullExtent(this.extent, FaweCache.NO_REGION); - } else { - if (allowedRegions.length == 1) { - regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); - } else { - regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, null); - } - } - } else { - allowedRegions = new Region[]{RegionWrapper.GLOBAL()}; - } - // There's no need to do lighting (and it'll also just be a pain to implement) if we're not placing chunks - if (placeChunks) { - if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.IMP.LIGHTING.MODE > 0))) { - relighter = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING) - .getRelighterFactory().createRelighter(relightMode, world, queue); - extent.addProcessor(new RelightProcessor(relighter)); - } - extent.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY())); - } else { - relighter = NullRelighter.INSTANCE; - } - if (limit != null && !limit.isUnlimited() && regionExtent != null) { - this.extent = new LimitExtent(regionExtent, limit); - } else if (limit != null && !limit.isUnlimited()) { - this.extent = new LimitExtent(this.extent, limit); - } else if (regionExtent != null) { - this.extent = regionExtent; - } - if (this.limit != null && this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { - if (placeChunks) { - extent.addProcessor(new StripNBTExtent(this.extent, this.limit.STRIP_NBT)); - } else { - this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); - } - } - this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY); - } - return this; - } - - public EditSession build() { - return new EditSession(this); - } - - @Nonnull - public World getWorld() { - return world; - } - - public Extent getExtent() { - return extent != null ? extent : world; - } - - public boolean isWrapped() { - return wrapped; - } - - public Extent getBypassHistory() { - return bypassHistory; - } - - public Extent getBypassAll() { - return bypassAll; - } - - @Nonnull - public FaweLimit getLimit() { - return limit; - } - - public Player getPlayer() { - return player; - } - - public AbstractChangeSet getChangeTask() { - return changeTask; - } - - public BlockBag getBlockBag() { - return blockBag; - } - - public Relighter getRelighter() { - return relighter; - } - - public boolean isWNAMode() { - return wnaMode; - } - - @Nullable - public Region[] getAllowedRegions() { - return allowedRegions; - } - - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index d6fa8f5d1..ae64b274e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -115,7 +115,7 @@ public class MainUtil { public static long getTotalSize(Path path) { final AtomicLong size = new AtomicLong(0); - traverse(path, new RunnableVal2() { + traverse(path, new RunnableVal2<>() { @Override public void run(Path path, BasicFileAttributes attrs) { size.addAndGet(attrs.size()); @@ -126,7 +126,7 @@ public class MainUtil { public static void traverse(Path path, final BiConsumer onEach) { try { - Files.walkFileTree(path, new SimpleFileVisitor() { + Files.walkFileTree(path, new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { @@ -231,20 +231,19 @@ public class MainUtil { } public static long getSize(ChangeSet changeSet) { - if (changeSet instanceof FaweStreamChangeSet) { - FaweStreamChangeSet fscs = (FaweStreamChangeSet) changeSet; + if (changeSet instanceof FaweStreamChangeSet fscs) { return fscs.getSizeOnDisk() + fscs.getSizeInMemory(); // } else if (changeSet instanceof CPUOptimizedChangeSet) { // return changeSet.size() + 32; } else if (changeSet != null) { - return changeSet.size() * 128; + return changeSet.size() * 128L; } else { return 0; } } public static FaweOutputStream getCompressedOS(OutputStream os, int amount) throws IOException { - return getCompressedOS(os, amount, Settings.IMP.HISTORY.BUFFER_SIZE); + return getCompressedOS(os, amount, Settings.settings().HISTORY.BUFFER_SIZE); } private static final LZ4Factory FACTORY = LZ4Factory.fastestInstance(); @@ -350,7 +349,7 @@ public class MainUtil { } public static FaweInputStream getCompressedIS(InputStream is) throws IOException { - return getCompressedIS(is, Settings.IMP.HISTORY.BUFFER_SIZE); + return getCompressedIS(is, Settings.settings().HISTORY.BUFFER_SIZE); } public static FaweInputStream getCompressedIS(InputStream is, int buffer) throws IOException { @@ -381,7 +380,7 @@ public class MainUtil { } public static URL upload(UUID uuid, String file, String extension, @Nonnull final RunnableVal writeTask) { - return upload(Settings.IMP.WEB.URL, uuid != null, uuid != null ? uuid.toString() : null, file, extension, writeTask); + return upload(Settings.settings().WEB.URL, uuid != null, uuid != null ? uuid.toString() : null, file, extension, writeTask); } public static URL upload( @@ -413,16 +412,15 @@ public class MainUtil { StandardCharsets.UTF_8 ), true)) { String crlf = "\r\n"; - writer.append("--" + boundary).append(crlf); + writer.append("--").append(boundary).append(crlf); writer.append("Content-Disposition: form-data; name=\"param\"").append(crlf); - writer.append("Content-Type: text/plain; charset=" + StandardCharsets.UTF_8.displayName()).append(crlf); + writer.append("Content-Type: text/plain; charset=").append(StandardCharsets.UTF_8.displayName()).append(crlf); String param = "value"; writer.append(crlf).append(param).append(crlf).flush(); - writer.append("--" + boundary).append(crlf); - writer - .append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" + filename + '"') + writer.append("--").append(boundary).append(crlf); + writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"").append(filename).append(String.valueOf('"')) .append(crlf); - writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(filename)).append(crlf); + writer.append("Content-Type: ").append(URLConnection.guessContentTypeFromName(filename)).append(crlf); writer.append("Content-Transfer-Encoding: binary").append(crlf); writer.append(crlf).flush(); OutputStream nonClosable = new AbstractDelegateOutputStream(new BufferedOutputStream(output)) { @@ -434,7 +432,7 @@ public class MainUtil { writeTask.run(); nonClosable.flush(); writer.append(crlf).flush(); - writer.append("--" + boundary + "--").append(crlf).flush(); + writer.append("--").append(boundary).append("--").append(crlf).flush(); } int responseCode = ((HttpURLConnection) con).getResponseCode(); String content; @@ -524,7 +522,7 @@ public class MainUtil { try { return getJarFile(Fawe.class); } catch (MalformedURLException | URISyntaxException | SecurityException e) { - return new File(Fawe.imp().getDirectory().getParentFile(), "FastAsyncWorldEdit.jar"); + return new File(Fawe.platform().getDirectory().getParentFile(), "FastAsyncWorldEdit.jar"); } } @@ -598,7 +596,7 @@ public class MainUtil { public static File copyFile(File jar, String resource, File output, String fileName) { try { if (output == null) { - output = Fawe.imp().getDirectory(); + output = Fawe.platform().getDirectory(); } if (!output.exists()) { output.mkdirs(); @@ -663,21 +661,19 @@ public class MainUtil { continue; } switch (c) { - case '-': - val = -val; - break; - case '.': + case '-' -> val = -val; + case '.' -> { res[index--] = val; if (index == -1) { return res; } val = 0; numIndex = 1; - break; - default: + } + default -> { val = val + (c - 48) * numIndex; numIndex *= 10; - break; + } } } res[index] = val; @@ -802,30 +798,30 @@ public class MainUtil { int years = (int) (time / 33868800); int time1 = years * 33868800; time -= time1; - toreturn.append(years + "y "); + toreturn.append(years).append("y "); } if (time >= 604800) { int weeks = (int) (time / 604800); - time -= weeks * 604800; - toreturn.append(weeks + "w "); + time -= weeks * 604800L; + toreturn.append(weeks).append("w "); } if (time >= 86400) { int days = (int) (time / 86400); - time -= days * 86400; - toreturn.append(days + "d "); + time -= days * 86400L; + toreturn.append(days).append("d "); } if (time >= 3600) { int hours = (int) (time / 3600); - time -= hours * 3600; - toreturn.append(hours + "h "); + time -= hours * 3600L; + toreturn.append(hours).append("h "); } if (time >= 60) { int minutes = (int) (time / 60); - time -= minutes * 60; - toreturn.append(minutes + "m "); + time -= minutes * 60L; + toreturn.append(minutes).append("m "); } if (toreturn.equals("") || time > 0) { - toreturn.append((time) + "s "); + toreturn.append(time).append("s "); } return toreturn.toString().trim(); } @@ -849,23 +845,23 @@ public class MainUtil { case "wks": case "w": - time += 604800 * nums; + time += 604800L * nums; case "days": case "day": case "d": - time += 86400 * nums; + time += 86400L * nums; case "hour": case "hr": case "hrs": case "hours": case "h": - time += 3600 * nums; + time += 3600L * nums; case "minutes": case "minute": case "mins": case "min": case "m": - time += 60 * nums; + time += 60L * nums; case "seconds": case "second": case "secs": diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MemUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MemUtil.java index 7aa4036ee..7760663ea 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MemUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MemUtil.java @@ -44,7 +44,7 @@ public class MemUtil { } final long heapFreeSize = Runtime.getRuntime().freeMemory(); final int size = (int) ((heapFreeSize * 100) / heapMaxSize); - if (size > (100 - Settings.IMP.MAX_MEMORY_PERCENT)) { + if (size > (100 - Settings.settings().MAX_MEMORY_PERCENT)) { memoryPlentifulTask(); return Integer.MAX_VALUE; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/StringMan.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/StringMan.java index f15e010ce..432acfe2d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/StringMan.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/StringMan.java @@ -9,11 +9,14 @@ import java.util.List; import java.util.Locale; import java.util.Set; import java.util.function.Function; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; public class StringMan { + private static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + public static boolean containsAny(CharSequence sequence, String any) { return IntStream.range(0, sequence.length()) .anyMatch(i -> any.indexOf(sequence.charAt(i)) != -1); @@ -542,4 +545,16 @@ public class StringMan { return IntStream.range(0, n).mapToObj(i -> s).collect(Collectors.joining()); } + /** + * Returns if there is a valid uuid contained inside the + * provided String. + * + * @param str provided string + * @return true if an uuid was found, false if not + * @since 2.0.0 + */ + public static boolean containsUuid(String str) { + return UUID_PATTERN.matcher(str).find(); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java index 9124d06e0..ad69c87d6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TaskManager.java @@ -21,10 +21,31 @@ public abstract class TaskManager { private static final Logger LOGGER = LogManagerCompat.getLogger(); + /** + * @deprecated Use {@link #taskManager()} to get an instance. + */ + @Deprecated(forRemoval = true, since = "2.0.0") public static TaskManager IMP; - + static TaskManager INSTANCE; private final ForkJoinPool pool = new ForkJoinPool(); + protected TaskManager() { + INSTANCE = this; + } + + /** + * Gets an instance of the TaskManager. + * + * @return an instance of the TaskManager + * @since 2.0.0 + */ + public static TaskManager taskManager() { + if (INSTANCE == null) { + INSTANCE = Fawe.platform().getTaskManager(); + } + return INSTANCE; + } + /** * Run a repeating task on the main thread. * @@ -68,8 +89,8 @@ public abstract class TaskManager { /** * Run a bunch of tasks in parallel using the shared thread pool. */ - public void parallel(Collection runnables) { - for (Runnable run : runnables) { + public void parallel(Collection runables) { + for (Runnable run : runables) { pool.submit(run); } pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); @@ -87,7 +108,7 @@ public abstract class TaskManager { return; } if (numThreads == null) { - numThreads = Settings.IMP.QUEUE.PARALLEL_THREADS; + numThreads = Settings.settings().QUEUE.PARALLEL_THREADS; } if (numThreads <= 1) { for (Runnable run : runnables) { @@ -135,7 +156,7 @@ public abstract class TaskManager { * Disable async catching for a specific task. */ public void runUnsafe(Runnable run) { - QueueHandler queue = Fawe.get().getQueueHandler(); + QueueHandler queue = Fawe.instance().getQueueHandler(); queue.startSet(true); try { run.run(); @@ -256,7 +277,7 @@ public abstract class TaskManager { synchronized (running) { while (running.get()) { running.wait(timeout); - if (running.get() && System.currentTimeMillis() - start > Settings.IMP.QUEUE.DISCARD_AFTER_MS) { + if (running.get() && System.currentTimeMillis() - start > Settings.settings().QUEUE.DISCARD_AFTER_MS) { new RuntimeException("FAWE is taking a long time to execute a task (might just be a symptom): ").printStackTrace(); LOGGER.info("For full debug information use: /fawe threads"); } @@ -278,7 +299,7 @@ public abstract class TaskManager { if (Fawe.isMainThread()) { run.run(); } else { - Fawe.get().getQueueHandler().sync(run); + Fawe.instance().getQueueHandler().sync(run); } } @@ -293,7 +314,7 @@ public abstract class TaskManager { return function.value; } try { - return Fawe.get().getQueueHandler().sync((Supplier) function).get(); + return Fawe.instance().getQueueHandler().sync((Supplier) function).get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -309,7 +330,7 @@ public abstract class TaskManager { return supplier.get(); } try { - return Fawe.get().getQueueHandler().sync(supplier).get(); + return Fawe.instance().getQueueHandler().sync(supplier).get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } @@ -334,7 +355,7 @@ public abstract class TaskManager { return function.get(); } try { - return Fawe.get().getQueueHandler().sync(function).get(); + return Fawe.instance().getQueueHandler().sync(function).get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java index ead803939..2a7da6939 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/TextureUtil.java @@ -33,7 +33,6 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.security.AccessControlException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -341,7 +340,7 @@ public class TextureUtil implements TextureHolder { * Do not use. Use {@link Fawe#getTextureUtil()} */ public TextureUtil() throws FileNotFoundException { - this(MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.TEXTURES)); + this(MainUtil.getFile(Fawe.platform().getDirectory(), Settings.settings().PATHS.TEXTURES)); } /** @@ -352,12 +351,12 @@ public class TextureUtil implements TextureHolder { if (!folder.exists()) { try { LOGGER.info("Downloading asset jar from Mojang, please wait..."); - new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/").mkdirs(); + new File(Fawe.platform().getDirectory() + "/" + Settings.settings().PATHS.TEXTURES + "/").mkdirs(); try (BufferedInputStream in = new BufferedInputStream( - new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") + new URL("https://launcher.mojang.com/v1/objects/7e46fb47609401970e2818989fa584fd467cd036/client.jar") .openStream()); FileOutputStream fileOutputStream = new FileOutputStream( - Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/1.17.1.jar")) { + Fawe.platform().getDirectory() + "/" + Settings.settings().PATHS.TEXTURES + "/1.18.1.jar")) { byte[] dataBuffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { @@ -370,7 +369,7 @@ public class TextureUtil implements TextureHolder { "folder with a `.minecraft/versions` jar in it."); LOGGER.error("If the file exists, please make sure the server has read access to the directory."); } - } catch (AccessControlException e) { + } catch (SecurityException e) { LOGGER.error( "Could not download asset jar. It's likely your file permission are setup improperly and do not allow fetching data from the Mojang servers."); LOGGER.error( @@ -396,7 +395,7 @@ public class TextureUtil implements TextureHolder { } public static TextureUtil fromBlocks(Set blocks) throws FileNotFoundException { - return new FilteredTextureUtil(Fawe.get().getTextureUtil(), blocks); + return new FilteredTextureUtil(Fawe.instance().getTextureUtil(), blocks); } public static TextureUtil fromMask(Mask mask) throws FileNotFoundException { @@ -405,7 +404,7 @@ public class TextureUtil implements TextureHolder { SingleFilterBlock extent = new SingleFilterBlock(); new MaskTraverser(mask).reset(extent); - TextureUtil tu = Fawe.get().getTextureUtil(); + TextureUtil tu = Fawe.instance().getTextureUtil(); for (int typeId : tu.getValidBlockIds()) { BlockType block = BlockTypes.get(typeId); extent.init(0, 0, 0, block.getDefaultState().toBaseBlock()); @@ -808,13 +807,13 @@ public class TextureUtil implements TextureHolder { // Get all the jar files File[] files = folder.listFiles((dir, name) -> name.endsWith(".jar")); if (files.length == 0) { - new File(Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/") + new File(Fawe.platform().getDirectory() + "/" + Settings.settings().PATHS.TEXTURES + "/") .mkdirs(); try (BufferedInputStream in = new BufferedInputStream( - new URL("https://launcher.mojang.com/v1/objects/8d9b65467c7913fcf6f5b2e729d44a1e00fde150/client.jar") + new URL("https://launcher.mojang.com/v1/objects/7e46fb47609401970e2818989fa584fd467cd036/client.jar") .openStream()); FileOutputStream fileOutputStream = new FileOutputStream( - Fawe.imp().getDirectory() + "/" + Settings.IMP.PATHS.TEXTURES + "/1.17.1.jar")) { + Fawe.platform().getDirectory() + "/" + Settings.settings().PATHS.TEXTURES + "/1.18.1.jar")) { byte[] dataBuffer = new byte[1024]; int bytesRead; while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java index 8e72ecc57..6425cfd14 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java @@ -1,23 +1,62 @@ package com.fastasyncworldedit.core.util; +import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.FaweVersion; +import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.net.URL; public class UpdateNotification { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static boolean hasUpdate; + private static String faweVersion = ""; + /** * Check whether a new build with a higher build number than the current build is available. */ public static void doUpdateCheck() { - if (Settings.IMP.ENABLED_COMPONENTS.UPDATE_NOTIFICATIONS) { - LOGGER.warn("An update for FastAsyncWorldEdit is available. Update at https://ci.athion.net/job/FastAsyncWorldEdit/"); + if (Settings.settings().ENABLED_COMPONENTS.UPDATE_NOTIFICATIONS) { + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse(new URL("https://ci.athion.net/job/FastAsyncWorldEdit/api/xml/").openStream()); + faweVersion = doc.getElementsByTagName("lastSuccessfulBuild").item(0).getFirstChild().getTextContent(); + FaweVersion faweVersion = Fawe.instance().getVersion(); + if (faweVersion.build == 0) { + LOGGER.warn("You are using a snapshot or a custom version of FAWE. This is not an official build distributed " + + "via https://www.spigotmc.org/resources/13932/"); + return; + } + if (faweVersion.build < Integer.parseInt(UpdateNotification.faweVersion)) { + hasUpdate = true; + int versionDifference = Integer.parseInt(UpdateNotification.faweVersion) - faweVersion.build; + LOGGER.warn( + """ + An update for FastAsyncWorldEdit is available. You are {} build(s) out of date. + You are running build {}, the latest version is build {}. + Update at https://www.spigotmc.org/resources/13932/""", + versionDifference, + faweVersion.build, + UpdateNotification.faweVersion + ); + } + } catch (Exception e) { + LOGGER.error("Unable to check for updates. Skipping."); + } + } } @@ -27,12 +66,19 @@ public class UpdateNotification { * @param actor The player to notify. */ public static void doUpdateNotification(Actor actor) { - if (Settings.IMP.ENABLED_COMPONENTS.UPDATE_NOTIFICATIONS) { - if (actor.hasPermission("fawe.admin")) { - actor.printInfo(TextComponent.of("An update for FastAsyncWorldEdit is available. Update at " + - "https://ci.athion.net/job/FastAsyncWorldEdit/").clickEvent(ClickEvent.openUrl("https://ci.athion.net/job/FastAsyncWorldEdit/")) - - ); + if (Settings.settings().ENABLED_COMPONENTS.UPDATE_NOTIFICATIONS) { + if (actor.hasPermission("fawe.admin") && UpdateNotification.hasUpdate) { + FaweVersion faweVersion = Fawe.instance().getVersion(); + int versionDifference = Integer.parseInt(UpdateNotification.faweVersion) - faweVersion.build; + actor.print(Caption.of( + "fawe.info.update-available", + versionDifference, + faweVersion.build, + UpdateNotification.faweVersion, + TextComponent + .of("https://www.spigotmc.org/resources/13932/") + .clickEvent(ClickEvent.openUrl("https://www.spigotmc.org/resources/13932/")) + )); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java index cbb5695ec..cf7e4f4de 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java @@ -26,10 +26,27 @@ import java.util.Set; public class WEManager { - public static final WEManager IMP = new WEManager(); private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static WEManager INSTANCE; + /** + * @deprecated Use {@link #weManager()} instead. + */ + @Deprecated(forRemoval = true, since = "2.0.0") + public static WEManager IMP = new WEManager(); private final ArrayDeque managers = new ArrayDeque<>(); + /** + * Get an instance of the WEManager. + * + * @return an instance of the WEManager + */ + public static WEManager weManager() { + if (INSTANCE == null) { + INSTANCE = new WEManager(); + } + return INSTANCE; + } + public ArrayDeque getManagers() { return managers; } @@ -81,7 +98,7 @@ public class WEManager { * @return array of allowed regions if whitelist, else of disallowed regions. */ public Region[] getMask(Player player, FaweMaskManager.MaskType type, final boolean isWhitelist) { - if (!Settings.IMP.REGION_RESTRICTIONS || player.hasPermission("fawe.bypass") || player.hasPermission("fawe.bypass.regions")) { + if (!Settings.settings().REGION_RESTRICTIONS || player.hasPermission("fawe.bypass") || player.hasPermission("fawe.bypass.regions")) { return new Region[]{RegionWrapper.GLOBAL()}; } Location loc = player.getLocation(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java index 6da6b471e..50512235c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/MemBlockSet.java @@ -22,7 +22,7 @@ import java.util.Set; public final class MemBlockSet extends BlockSet { public static final int BITS_PER_WORD = 6; - public static final int WORDS = FaweCache.IMP.BLOCKS_PER_LAYER >> BITS_PER_WORD; + public static final int WORDS = FaweCache.INSTANCE.BLOCKS_PER_LAYER >> BITS_PER_WORD; public static final IRow NULL_ROW_X = new NullRowX(); public static final IRow NULL_ROW_Z = new NullRowZ(); public static final IRow NULL_ROW_Y = new NullRowY(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java index ee8ee6251..a8998e1f0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/image/ImageUtil.java @@ -212,8 +212,8 @@ public class ImageUtil { if (arg.startsWith("file:/")) { arg = arg.replaceFirst("file:/+", ""); File file = MainUtil.getFile(MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HEIGHTMAP + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HEIGHTMAP ), arg); return MainUtil.readImage(file); } @@ -234,8 +234,8 @@ public class ImageUtil { if (arg.startsWith("file:/")) { arg = arg.replaceFirst("file:/+", ""); File file = MainUtil.getFile(MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HEIGHTMAP + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HEIGHTMAP ), arg); if (!file.exists()) { throw new InputParseException(Caption.of( diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/progress/DefaultProgressTracker.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/progress/DefaultProgressTracker.java index ef92296c0..c14ca93eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/progress/DefaultProgressTracker.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/progress/DefaultProgressTracker.java @@ -17,8 +17,8 @@ public class DefaultProgressTracker implements BiConsumer { this.task = new Runnable() { @Override public void run() { - long allowedTick = Fawe.get().getTimer().getTick() - 1; + long allowedTick = Fawe.instance().getTimer().getTick() - 1; Iterator> iter = objMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -32,7 +32,7 @@ public abstract class SingleThreadIntervalQueue { } synchronized (objMap) { if (!objMap.isEmpty()) { - TaskManager.IMP.laterAsync(this, interval); + TaskManager.taskManager().laterAsync(this, interval); } else { queued.set(false); } @@ -51,10 +51,10 @@ public abstract class SingleThreadIntervalQueue { public void queue(T obj) { synchronized (objMap) { - objMap.put(obj, Fawe.get().getTimer().getTick()); + objMap.put(obj, Fawe.instance().getTimer().getTick()); if (!queued.get()) { queued.set(true); - TaskManager.IMP.laterAsync(task, 3); + TaskManager.taskManager().laterAsync(task, 3); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java index 70c7abd9c..dcc65ae21 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/SimpleWorld.java @@ -97,7 +97,7 @@ public interface SimpleWorld extends World { @Override default boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { - Fawe.get().getQueueHandler().sync((Supplier) () -> playEffect( + Fawe.instance().getQueueHandler().sync((Supplier) () -> playEffect( position, 2001, blockType.getLegacyCombinedId() >> 4 diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/BlockID.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/BlockID.java deleted file mode 100644 index c077c7f53..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/world/block/BlockID.java +++ /dev/null @@ -1,695 +0,0 @@ -package com.fastasyncworldedit.core.world.block; - -/** - * An internal FAWE class used for switch statements on blocks. - * Using IDs to register items is pre 1.13 days. This class is - * deprecated for removal with replacement of namespaced IDs. - */ -@Deprecated(forRemoval = true) -public class BlockID { - - public static final int __RESERVED__ = 0; - public static final int AIR = 1; - public static final int CAVE_AIR = 2; - public static final int VOID_AIR = 3; - public static final int ACACIA_BUTTON = 4; - public static final int ACACIA_DOOR = 5; - public static final int ACACIA_FENCE = 6; - public static final int ACACIA_FENCE_GATE = 7; - public static final int ACACIA_LEAVES = 8; - public static final int ACACIA_LOG = 9; - public static final int ACACIA_PLANKS = 10; - public static final int ACACIA_PRESSURE_PLATE = 11; - public static final int ACACIA_SAPLING = 12; - public static final int ACACIA_SIGN = 501; - public static final int ACACIA_SLAB = 13; - public static final int ACACIA_STAIRS = 14; - public static final int ACACIA_TRAPDOOR = 15; - public static final int ACACIA_WALL_SIGN = 565; - public static final int ACACIA_WOOD = 16; - public static final int ACTIVATOR_RAIL = 17; - public static final int ALLIUM = 18; - public static final int ANDESITE = 19; - public static final int ANDESITE_SLAB = 599; - public static final int ANDESITE_STAIRS = 600; - public static final int ANDESITE_WALL = 601; - public static final int ANVIL = 20; - public static final int ATTACHED_MELON_STEM = 21; - public static final int ATTACHED_PUMPKIN_STEM = 22; - public static final int AZURE_BLUET = 23; - public static final int BAMBOO = 602; - public static final int BAMBOO_SAPLING = 603; - public static final int BARREL = 604; - public static final int BARRIER = 24; - public static final int BEACON = 25; - public static final int BEDROCK = 26; - public static final int BEE_NEST = 677; - public static final int BEEHIVE = 678; // highest - public static final int BEETROOTS = 27; - public static final int BELL = 605; - public static final int BIRCH_BUTTON = 28; - public static final int BIRCH_DOOR = 29; - public static final int BIRCH_FENCE = 30; - public static final int BIRCH_FENCE_GATE = 31; - public static final int BIRCH_LEAVES = 32; - public static final int BIRCH_LOG = 33; - public static final int BIRCH_PLANKS = 34; - public static final int BIRCH_PRESSURE_PLATE = 35; - public static final int BIRCH_SAPLING = 36; - public static final int BIRCH_SIGN = 606; - public static final int BIRCH_SLAB = 37; - public static final int BIRCH_STAIRS = 38; - public static final int BIRCH_TRAPDOOR = 39; - public static final int BIRCH_WALL_SIGN = 607; - public static final int BIRCH_WOOD = 40; - public static final int BLACK_BANNER = 41; - public static final int BLACK_BED = 42; - public static final int BLACK_CARPET = 43; - public static final int BLACK_CONCRETE = 44; - public static final int BLACK_CONCRETE_POWDER = 45; - public static final int BLACK_GLAZED_TERRACOTTA = 46; - public static final int BLACK_SHULKER_BOX = 47; - public static final int BLACK_STAINED_GLASS = 48; - public static final int BLACK_STAINED_GLASS_PANE = 49; - public static final int BLACK_TERRACOTTA = 50; - public static final int BLACK_WALL_BANNER = 51; - public static final int BLACK_WOOL = 52; - public static final int BLAST_FURNACE = 608; - public static final int BLUE_BANNER = 53; - public static final int BLUE_BED = 54; - public static final int BLUE_CARPET = 55; - public static final int BLUE_CONCRETE = 56; - public static final int BLUE_CONCRETE_POWDER = 57; - public static final int BLUE_GLAZED_TERRACOTTA = 58; - public static final int BLUE_ICE = 59; - public static final int BLUE_ORCHID = 60; - public static final int BLUE_SHULKER_BOX = 61; - public static final int BLUE_STAINED_GLASS = 62; - public static final int BLUE_STAINED_GLASS_PANE = 63; - public static final int BLUE_TERRACOTTA = 64; - public static final int BLUE_WALL_BANNER = 65; - public static final int BLUE_WOOL = 66; - public static final int BONE_BLOCK = 67; - public static final int BOOKSHELF = 68; - public static final int BRAIN_CORAL = 69; - public static final int BRAIN_CORAL_BLOCK = 70; - public static final int BRAIN_CORAL_FAN = 71; - public static final int BRAIN_CORAL_WALL_FAN = 72; - public static final int BREWING_STAND = 73; - public static final int BRICK_SLAB = 74; - public static final int BRICK_STAIRS = 75; - public static final int BRICK_WALL = 609; - public static final int BRICKS = 76; - public static final int BROWN_BANNER = 77; - public static final int BROWN_BED = 78; - public static final int BROWN_CARPET = 79; - public static final int BROWN_CONCRETE = 80; - public static final int BROWN_CONCRETE_POWDER = 81; - public static final int BROWN_GLAZED_TERRACOTTA = 82; - public static final int BROWN_MUSHROOM = 83; - public static final int BROWN_MUSHROOM_BLOCK = 84; - public static final int BROWN_SHULKER_BOX = 85; - public static final int BROWN_STAINED_GLASS = 86; - public static final int BROWN_STAINED_GLASS_PANE = 87; - public static final int BROWN_TERRACOTTA = 88; - public static final int BROWN_WALL_BANNER = 89; - public static final int BROWN_WOOL = 90; - public static final int BUBBLE_COLUMN = 91; - public static final int BUBBLE_CORAL = 92; - public static final int BUBBLE_CORAL_BLOCK = 93; - public static final int BUBBLE_CORAL_FAN = 94; - public static final int BUBBLE_CORAL_WALL_FAN = 95; - public static final int CACTUS = 96; - public static final int CAKE = 97; - public static final int CAMPFIRE = 610; - public static final int CARROTS = 98; - public static final int CARTOGRAPHY_TABLE = 611; - public static final int CARVED_PUMPKIN = 99; - public static final int CAULDRON = 100; - public static final int CHAIN_COMMAND_BLOCK = 101; - public static final int CHEST = 102; - public static final int CHIPPED_ANVIL = 103; - public static final int CHISELED_QUARTZ_BLOCK = 104; - public static final int CHISELED_RED_SANDSTONE = 105; - public static final int CHISELED_SANDSTONE = 106; - public static final int CHISELED_STONE_BRICKS = 107; - public static final int CHORUS_FLOWER = 108; - public static final int CHORUS_PLANT = 109; - public static final int CLAY = 110; - public static final int COAL_BLOCK = 111; - public static final int COAL_ORE = 112; - public static final int COARSE_DIRT = 113; - public static final int COBBLESTONE = 114; - public static final int COBBLESTONE_SLAB = 115; - public static final int COBBLESTONE_STAIRS = 116; - public static final int COBBLESTONE_WALL = 117; - public static final int COBWEB = 118; - public static final int COCOA = 119; - public static final int COMMAND_BLOCK = 120; - public static final int COMPARATOR = 121; - public static final int COMPOSTER = 612; - public static final int CONDUIT = 122; - public static final int CORNFLOWER = 613; - public static final int CRACKED_STONE_BRICKS = 123; - public static final int CRAFTING_TABLE = 124; - public static final int CREEPER_HEAD = 125; - public static final int CREEPER_WALL_HEAD = 126; - public static final int CUT_RED_SANDSTONE = 127; - public static final int CUT_RED_SANDSTONE_SLAB = 614; - public static final int CUT_SANDSTONE = 128; - public static final int CUT_SANDSTONE_SLAB = 615; - public static final int CYAN_BANNER = 129; - public static final int CYAN_BED = 130; - public static final int CYAN_CARPET = 131; - public static final int CYAN_CONCRETE = 132; - public static final int CYAN_CONCRETE_POWDER = 133; - public static final int CYAN_GLAZED_TERRACOTTA = 134; - public static final int CYAN_SHULKER_BOX = 135; - public static final int CYAN_STAINED_GLASS = 136; - public static final int CYAN_STAINED_GLASS_PANE = 137; - public static final int CYAN_TERRACOTTA = 138; - public static final int CYAN_WALL_BANNER = 139; - public static final int CYAN_WOOL = 140; - public static final int DAMAGED_ANVIL = 141; - public static final int DANDELION = 142; - public static final int DARK_OAK_BUTTON = 143; - public static final int DARK_OAK_DOOR = 144; - public static final int DARK_OAK_FENCE = 145; - public static final int DARK_OAK_FENCE_GATE = 146; - public static final int DARK_OAK_LEAVES = 147; - public static final int DARK_OAK_LOG = 148; - public static final int DARK_OAK_PLANKS = 149; - public static final int DARK_OAK_PRESSURE_PLATE = 150; - public static final int DARK_OAK_SAPLING = 151; - public static final int DARK_OAK_SIGN = 616; - public static final int DARK_OAK_SLAB = 152; - public static final int DARK_OAK_STAIRS = 153; - public static final int DARK_OAK_TRAPDOOR = 154; - public static final int DARK_OAK_WALL_SIGN = 617; - public static final int DARK_OAK_WOOD = 155; - public static final int DARK_PRISMARINE = 156; - public static final int DARK_PRISMARINE_SLAB = 157; - public static final int DARK_PRISMARINE_STAIRS = 158; - public static final int DAYLIGHT_DETECTOR = 159; - public static final int DEAD_BRAIN_CORAL = 160; - public static final int DEAD_BRAIN_CORAL_BLOCK = 161; - public static final int DEAD_BRAIN_CORAL_FAN = 162; - public static final int DEAD_BRAIN_CORAL_WALL_FAN = 163; - public static final int DEAD_BUBBLE_CORAL = 164; - public static final int DEAD_BUBBLE_CORAL_BLOCK = 165; - public static final int DEAD_BUBBLE_CORAL_FAN = 166; - public static final int DEAD_BUBBLE_CORAL_WALL_FAN = 167; - public static final int DEAD_BUSH = 168; - public static final int DEAD_FIRE_CORAL = 169; - public static final int DEAD_FIRE_CORAL_BLOCK = 170; - public static final int DEAD_FIRE_CORAL_FAN = 171; - public static final int DEAD_FIRE_CORAL_WALL_FAN = 172; - public static final int DEAD_HORN_CORAL = 173; - public static final int DEAD_HORN_CORAL_BLOCK = 174; - public static final int DEAD_HORN_CORAL_FAN = 175; - public static final int DEAD_HORN_CORAL_WALL_FAN = 176; - public static final int DEAD_TUBE_CORAL = 177; - public static final int DEAD_TUBE_CORAL_BLOCK = 178; - public static final int DEAD_TUBE_CORAL_FAN = 179; - public static final int DEAD_TUBE_CORAL_WALL_FAN = 180; - public static final int DETECTOR_RAIL = 181; - public static final int DIAMOND_BLOCK = 182; - public static final int DIAMOND_ORE = 183; - public static final int DIORITE = 184; - public static final int DIORITE_SLAB = 618; - public static final int DIORITE_STAIRS = 619; - public static final int DIORITE_WALL = 620; - public static final int DIRT = 185; - public static final int DISPENSER = 186; - public static final int DRAGON_EGG = 187; - public static final int DRAGON_HEAD = 188; - public static final int DRAGON_WALL_HEAD = 189; - public static final int DRIED_KELP_BLOCK = 190; - public static final int DROPPER = 191; - public static final int EMERALD_BLOCK = 192; - public static final int EMERALD_ORE = 193; - public static final int ENCHANTING_TABLE = 194; - public static final int END_GATEWAY = 195; - public static final int END_PORTAL = 196; - public static final int END_PORTAL_FRAME = 197; - public static final int END_ROD = 198; - public static final int END_STONE = 199; - public static final int END_STONE_BRICK_SLAB = 621; - public static final int END_STONE_BRICK_STAIRS = 622; - public static final int END_STONE_BRICK_WALL = 623; - public static final int END_STONE_BRICKS = 200; - public static final int ENDER_CHEST = 201; - public static final int FARMLAND = 202; - public static final int FERN = 203; - public static final int FIRE = 204; - public static final int FIRE_CORAL = 205; - public static final int FIRE_CORAL_BLOCK = 206; - public static final int FIRE_CORAL_FAN = 207; - public static final int FIRE_CORAL_WALL_FAN = 208; - public static final int FLETCHING_TABLE = 624; - public static final int FLOWER_POT = 209; - public static final int FROSTED_ICE = 210; - public static final int FURNACE = 211; - public static final int GLASS = 212; - public static final int GLASS_PANE = 213; - public static final int GLOWSTONE = 214; - public static final int GOLD_BLOCK = 215; - public static final int GOLD_ORE = 216; - public static final int GRANITE = 217; - public static final int GRANITE_SLAB = 625; - public static final int GRANITE_STAIRS = 626; - public static final int GRANITE_WALL = 627; - public static final int GRASS = 218; - public static final int GRASS_BLOCK = 219; - public static final int GRASS_PATH = 220; - public static final int GRAVEL = 221; - public static final int GRAY_BANNER = 222; - public static final int GRAY_BED = 223; - public static final int GRAY_CARPET = 224; - public static final int GRAY_CONCRETE = 225; - public static final int GRAY_CONCRETE_POWDER = 226; - public static final int GRAY_GLAZED_TERRACOTTA = 227; - public static final int GRAY_SHULKER_BOX = 228; - public static final int GRAY_STAINED_GLASS = 229; - public static final int GRAY_STAINED_GLASS_PANE = 230; - public static final int GRAY_TERRACOTTA = 231; - public static final int GRAY_WALL_BANNER = 232; - public static final int GRAY_WOOL = 233; - public static final int GREEN_BANNER = 234; - public static final int GREEN_BED = 235; - public static final int GREEN_CARPET = 236; - public static final int GREEN_CONCRETE = 237; - public static final int GREEN_CONCRETE_POWDER = 238; - public static final int GREEN_GLAZED_TERRACOTTA = 239; - public static final int GREEN_SHULKER_BOX = 240; - public static final int GREEN_STAINED_GLASS = 241; - public static final int GREEN_STAINED_GLASS_PANE = 242; - public static final int GREEN_TERRACOTTA = 243; - public static final int GREEN_WALL_BANNER = 244; - public static final int GREEN_WOOL = 245; - public static final int GRINDSTONE = 628; - public static final int HAY_BLOCK = 246; - public static final int HEAVY_WEIGHTED_PRESSURE_PLATE = 247; - public static final int HOPPER = 248; - public static final int HORN_CORAL = 249; - public static final int HORN_CORAL_BLOCK = 250; - public static final int HORN_CORAL_FAN = 251; - public static final int HORN_CORAL_WALL_FAN = 252; - public static final int ICE = 253; - public static final int INFESTED_CHISELED_STONE_BRICKS = 254; - public static final int INFESTED_COBBLESTONE = 255; - public static final int INFESTED_CRACKED_STONE_BRICKS = 256; - public static final int INFESTED_MOSSY_STONE_BRICKS = 257; - public static final int INFESTED_STONE = 258; - public static final int INFESTED_STONE_BRICKS = 259; - public static final int IRON_BARS = 260; - public static final int IRON_BLOCK = 261; - public static final int IRON_DOOR = 262; - public static final int IRON_ORE = 263; - public static final int IRON_TRAPDOOR = 264; - public static final int JACK_O_LANTERN = 265; - public static final int JIGSAW = 629; - public static final int JUKEBOX = 266; - public static final int JUNGLE_BUTTON = 267; - public static final int JUNGLE_DOOR = 268; - public static final int JUNGLE_FENCE = 269; - public static final int JUNGLE_FENCE_GATE = 270; - public static final int JUNGLE_LEAVES = 271; - public static final int JUNGLE_LOG = 272; - public static final int JUNGLE_PLANKS = 273; - public static final int JUNGLE_PRESSURE_PLATE = 274; - public static final int JUNGLE_SAPLING = 275; - public static final int JUNGLE_SIGN = 630; - public static final int JUNGLE_SLAB = 276; - public static final int JUNGLE_STAIRS = 277; - public static final int JUNGLE_TRAPDOOR = 278; - public static final int JUNGLE_WALL_SIGN = 631; - public static final int JUNGLE_WOOD = 279; - public static final int KELP = 280; - public static final int KELP_PLANT = 281; - public static final int LADDER = 282; - public static final int LANTERN = 632; - public static final int LAPIS_BLOCK = 283; - public static final int LAPIS_ORE = 284; - public static final int LARGE_FERN = 285; - public static final int LAVA = 286; - public static final int LECTERN = 633; - public static final int LEVER = 287; - public static final int LIGHT_BLUE_BANNER = 288; - public static final int LIGHT_BLUE_BED = 289; - public static final int LIGHT_BLUE_CARPET = 290; - public static final int LIGHT_BLUE_CONCRETE = 291; - public static final int LIGHT_BLUE_CONCRETE_POWDER = 292; - public static final int LIGHT_BLUE_GLAZED_TERRACOTTA = 293; - public static final int LIGHT_BLUE_SHULKER_BOX = 294; - public static final int LIGHT_BLUE_STAINED_GLASS = 295; - public static final int LIGHT_BLUE_STAINED_GLASS_PANE = 296; - public static final int LIGHT_BLUE_TERRACOTTA = 297; - public static final int LIGHT_BLUE_WALL_BANNER = 298; - public static final int LIGHT_BLUE_WOOL = 299; - public static final int LIGHT_GRAY_BANNER = 300; - public static final int LIGHT_GRAY_BED = 301; - public static final int LIGHT_GRAY_CARPET = 302; - public static final int LIGHT_GRAY_CONCRETE = 303; - public static final int LIGHT_GRAY_CONCRETE_POWDER = 304; - public static final int LIGHT_GRAY_GLAZED_TERRACOTTA = 305; - public static final int LIGHT_GRAY_SHULKER_BOX = 306; - public static final int LIGHT_GRAY_STAINED_GLASS = 307; - public static final int LIGHT_GRAY_STAINED_GLASS_PANE = 308; - public static final int LIGHT_GRAY_TERRACOTTA = 309; - public static final int LIGHT_GRAY_WALL_BANNER = 310; - public static final int LIGHT_GRAY_WOOL = 311; - public static final int LIGHT_WEIGHTED_PRESSURE_PLATE = 312; - public static final int LILAC = 313; - public static final int LILY_OF_THE_VALLEY = 634; - public static final int LILY_PAD = 314; - public static final int LIME_BANNER = 315; - public static final int LIME_BED = 316; - public static final int LIME_CARPET = 317; - public static final int LIME_CONCRETE = 318; - public static final int LIME_CONCRETE_POWDER = 319; - public static final int LIME_GLAZED_TERRACOTTA = 320; - public static final int LIME_SHULKER_BOX = 321; - public static final int LIME_STAINED_GLASS = 322; - public static final int LIME_STAINED_GLASS_PANE = 323; - public static final int LIME_TERRACOTTA = 324; - public static final int LIME_WALL_BANNER = 325; - public static final int LIME_WOOL = 326; - public static final int LOOM = 635; - public static final int MAGENTA_BANNER = 327; - public static final int MAGENTA_BED = 328; - public static final int MAGENTA_CARPET = 329; - public static final int MAGENTA_CONCRETE = 330; - public static final int MAGENTA_CONCRETE_POWDER = 331; - public static final int MAGENTA_GLAZED_TERRACOTTA = 332; - public static final int MAGENTA_SHULKER_BOX = 333; - public static final int MAGENTA_STAINED_GLASS = 334; - public static final int MAGENTA_STAINED_GLASS_PANE = 335; - public static final int MAGENTA_TERRACOTTA = 336; - public static final int MAGENTA_WALL_BANNER = 337; - public static final int MAGENTA_WOOL = 338; - public static final int MAGMA_BLOCK = 339; - public static final int MELON = 340; - public static final int MELON_STEM = 341; - public static final int MOSSY_COBBLESTONE = 342; - public static final int MOSSY_COBBLESTONE_SLAB = 636; - public static final int MOSSY_COBBLESTONE_STAIRS = 637; - public static final int MOSSY_COBBLESTONE_WALL = 343; - public static final int MOSSY_STONE_BRICK_SLAB = 638; - public static final int MOSSY_STONE_BRICK_STAIRS = 639; - public static final int MOSSY_STONE_BRICK_WALL = 640; - public static final int MOSSY_STONE_BRICKS = 344; - public static final int MOVING_PISTON = 345; - public static final int MUSHROOM_STEM = 346; - public static final int MYCELIUM = 347; - public static final int NETHER_BRICK_FENCE = 348; - public static final int NETHER_BRICK_SLAB = 349; - public static final int NETHER_BRICK_STAIRS = 350; - public static final int NETHER_BRICK_WALL = 641; - public static final int NETHER_BRICKS = 351; - public static final int NETHER_PORTAL = 352; - public static final int NETHER_QUARTZ_ORE = 353; - public static final int NETHER_WART = 354; - public static final int NETHER_WART_BLOCK = 355; - public static final int NETHERRACK = 356; - public static final int NOTE_BLOCK = 357; - public static final int OAK_BUTTON = 358; - public static final int OAK_DOOR = 359; - public static final int OAK_FENCE = 360; - public static final int OAK_FENCE_GATE = 361; - public static final int OAK_LEAVES = 362; - public static final int OAK_LOG = 363; - public static final int OAK_PLANKS = 364; - public static final int OAK_PRESSURE_PLATE = 365; - public static final int OAK_SAPLING = 366; - public static final int OAK_SIGN = 642; - public static final int OAK_SLAB = 367; - public static final int OAK_STAIRS = 368; - public static final int OAK_TRAPDOOR = 369; - public static final int OAK_WALL_SIGN = 643; - public static final int OAK_WOOD = 370; - public static final int OBSERVER = 371; - public static final int OBSIDIAN = 372; - public static final int ORANGE_BANNER = 373; - public static final int ORANGE_BED = 374; - public static final int ORANGE_CARPET = 375; - public static final int ORANGE_CONCRETE = 376; - public static final int ORANGE_CONCRETE_POWDER = 377; - public static final int ORANGE_GLAZED_TERRACOTTA = 378; - public static final int ORANGE_SHULKER_BOX = 379; - public static final int ORANGE_STAINED_GLASS = 380; - public static final int ORANGE_STAINED_GLASS_PANE = 381; - public static final int ORANGE_TERRACOTTA = 382; - public static final int ORANGE_TULIP = 383; - public static final int ORANGE_WALL_BANNER = 384; - public static final int ORANGE_WOOL = 385; - public static final int OXEYE_DAISY = 386; - public static final int PACKED_ICE = 387; - public static final int PEONY = 388; - public static final int PETRIFIED_OAK_SLAB = 389; - public static final int PINK_BANNER = 390; - public static final int PINK_BED = 391; - public static final int PINK_CARPET = 392; - public static final int PINK_CONCRETE = 393; - public static final int PINK_CONCRETE_POWDER = 394; - public static final int PINK_GLAZED_TERRACOTTA = 395; - public static final int PINK_SHULKER_BOX = 396; - public static final int PINK_STAINED_GLASS = 397; - public static final int PINK_STAINED_GLASS_PANE = 398; - public static final int PINK_TERRACOTTA = 399; - public static final int PINK_TULIP = 400; - public static final int PINK_WALL_BANNER = 401; - public static final int PINK_WOOL = 402; - public static final int PISTON = 403; - public static final int PISTON_HEAD = 404; - public static final int PLAYER_HEAD = 405; - public static final int PLAYER_WALL_HEAD = 406; - public static final int PODZOL = 407; - public static final int POLISHED_ANDESITE = 408; - public static final int POLISHED_ANDESITE_SLAB = 644; - public static final int POLISHED_ANDESITE_STAIRS = 645; - public static final int POLISHED_DIORITE = 409; - public static final int POLISHED_DIORITE_SLAB = 646; - public static final int POLISHED_DIORITE_STAIRS = 647; - public static final int POLISHED_GRANITE = 410; - public static final int POLISHED_GRANITE_SLAB = 648; - public static final int POLISHED_GRANITE_STAIRS = 649; - public static final int POPPY = 411; - public static final int POTATOES = 412; - public static final int POTTED_ACACIA_SAPLING = 413; - public static final int POTTED_ALLIUM = 414; - public static final int POTTED_AZURE_BLUET = 415; - public static final int POTTED_BAMBOO = 650; - public static final int POTTED_BIRCH_SAPLING = 416; - public static final int POTTED_BLUE_ORCHID = 417; - public static final int POTTED_BROWN_MUSHROOM = 418; - public static final int POTTED_CACTUS = 419; - public static final int POTTED_CORNFLOWER = 651; - public static final int POTTED_DANDELION = 420; - public static final int POTTED_DARK_OAK_SAPLING = 421; - public static final int POTTED_DEAD_BUSH = 422; - public static final int POTTED_FERN = 423; - public static final int POTTED_JUNGLE_SAPLING = 424; - public static final int POTTED_LILY_OF_THE_VALLEY = 652; - public static final int POTTED_OAK_SAPLING = 425; - public static final int POTTED_ORANGE_TULIP = 426; - public static final int POTTED_OXEYE_DAISY = 427; - public static final int POTTED_PINK_TULIP = 428; - public static final int POTTED_POPPY = 429; - public static final int POTTED_RED_MUSHROOM = 430; - public static final int POTTED_RED_TULIP = 431; - public static final int POTTED_SPRUCE_SAPLING = 432; - public static final int POTTED_WHITE_TULIP = 433; - public static final int POTTED_WITHER_ROSE = 653; - public static final int POWERED_RAIL = 434; - public static final int PRISMARINE = 435; - public static final int PRISMARINE_BRICK_SLAB = 436; - public static final int PRISMARINE_BRICK_STAIRS = 437; - public static final int PRISMARINE_BRICKS = 438; - public static final int PRISMARINE_SLAB = 439; - public static final int PRISMARINE_STAIRS = 440; - public static final int PRISMARINE_WALL = 654; - public static final int PUMPKIN = 441; - public static final int PUMPKIN_STEM = 442; - public static final int PURPLE_BANNER = 443; - public static final int PURPLE_BED = 444; - public static final int PURPLE_CARPET = 445; - public static final int PURPLE_CONCRETE = 446; - public static final int PURPLE_CONCRETE_POWDER = 447; - public static final int PURPLE_GLAZED_TERRACOTTA = 448; - public static final int PURPLE_SHULKER_BOX = 449; - public static final int PURPLE_STAINED_GLASS = 450; - public static final int PURPLE_STAINED_GLASS_PANE = 451; - public static final int PURPLE_TERRACOTTA = 452; - public static final int PURPLE_WALL_BANNER = 453; - public static final int PURPLE_WOOL = 454; - public static final int PURPUR_BLOCK = 455; - public static final int PURPUR_PILLAR = 456; - public static final int PURPUR_SLAB = 457; - public static final int PURPUR_STAIRS = 458; - public static final int QUARTZ_BLOCK = 459; - public static final int QUARTZ_PILLAR = 460; - public static final int QUARTZ_SLAB = 461; - public static final int QUARTZ_STAIRS = 462; - public static final int RAIL = 463; - public static final int RED_BANNER = 464; - public static final int RED_BED = 465; - public static final int RED_CARPET = 466; - public static final int RED_CONCRETE = 467; - public static final int RED_CONCRETE_POWDER = 468; - public static final int RED_GLAZED_TERRACOTTA = 469; - public static final int RED_MUSHROOM = 470; - public static final int RED_MUSHROOM_BLOCK = 471; - public static final int RED_NETHER_BRICK_SLAB = 655; - public static final int RED_NETHER_BRICK_STAIRS = 656; - public static final int RED_NETHER_BRICK_WALL = 657; - public static final int RED_NETHER_BRICKS = 472; - public static final int RED_SAND = 473; - public static final int RED_SANDSTONE = 474; - public static final int RED_SANDSTONE_SLAB = 475; - public static final int RED_SANDSTONE_STAIRS = 476; - public static final int RED_SANDSTONE_WALL = 658; - public static final int RED_SHULKER_BOX = 477; - public static final int RED_STAINED_GLASS = 478; - public static final int RED_STAINED_GLASS_PANE = 479; - public static final int RED_TERRACOTTA = 480; - public static final int RED_TULIP = 481; - public static final int RED_WALL_BANNER = 482; - public static final int RED_WOOL = 483; - public static final int REDSTONE_BLOCK = 484; - public static final int REDSTONE_LAMP = 485; - public static final int REDSTONE_ORE = 486; - public static final int REDSTONE_TORCH = 487; - public static final int REDSTONE_WALL_TORCH = 488; - public static final int REDSTONE_WIRE = 489; - public static final int REPEATER = 490; - public static final int REPEATING_COMMAND_BLOCK = 491; - public static final int ROSE_BUSH = 492; - public static final int SAND = 493; - public static final int SANDSTONE = 494; - public static final int SANDSTONE_SLAB = 495; - public static final int SANDSTONE_STAIRS = 496; - public static final int SANDSTONE_WALL = 659; - public static final int SCAFFOLDING = 660; - public static final int SEA_LANTERN = 497; - public static final int SEA_PICKLE = 498; - public static final int SEAGRASS = 499; - public static final int SHULKER_BOX = 500; - public static final int SKELETON_SKULL = 502; - public static final int SKELETON_WALL_SKULL = 503; - public static final int SLIME_BLOCK = 504; - public static final int SMITHING_TABLE = 661; - public static final int SMOKER = 662; - public static final int SMOOTH_QUARTZ = 505; - public static final int SMOOTH_QUARTZ_SLAB = 663; - public static final int SMOOTH_QUARTZ_STAIRS = 664; - public static final int SMOOTH_RED_SANDSTONE = 506; - public static final int SMOOTH_RED_SANDSTONE_SLAB = 665; - public static final int SMOOTH_RED_SANDSTONE_STAIRS = 666; - public static final int SMOOTH_SANDSTONE = 507; - public static final int SMOOTH_SANDSTONE_SLAB = 667; - public static final int SMOOTH_SANDSTONE_STAIRS = 668; - public static final int SMOOTH_STONE = 508; - public static final int SMOOTH_STONE_SLAB = 669; - public static final int SNOW = 509; - public static final int SNOW_BLOCK = 510; - public static final int SOUL_SAND = 511; - public static final int SPAWNER = 512; - public static final int SPONGE = 513; - public static final int SPRUCE_BUTTON = 514; - public static final int SPRUCE_DOOR = 515; - public static final int SPRUCE_FENCE = 516; - public static final int SPRUCE_FENCE_GATE = 517; - public static final int SPRUCE_LEAVES = 518; - public static final int SPRUCE_LOG = 519; - public static final int SPRUCE_PLANKS = 520; - public static final int SPRUCE_PRESSURE_PLATE = 521; - public static final int SPRUCE_SAPLING = 522; - public static final int SPRUCE_SIGN = 670; - public static final int SPRUCE_SLAB = 523; - public static final int SPRUCE_STAIRS = 524; - public static final int SPRUCE_TRAPDOOR = 525; - public static final int SPRUCE_WALL_SIGN = 671; - public static final int SPRUCE_WOOD = 526; - public static final int STICKY_PISTON = 527; - public static final int STONE = 528; - public static final int STONE_BRICK_SLAB = 529; - public static final int STONE_BRICK_STAIRS = 530; - public static final int STONE_BRICK_WALL = 672; - public static final int STONE_BRICKS = 531; - public static final int STONE_BUTTON = 532; - public static final int STONE_PRESSURE_PLATE = 533; - public static final int STONE_SLAB = 534; - public static final int STONE_STAIRS = 673; - public static final int STONECUTTER = 674; - public static final int STRIPPED_ACACIA_LOG = 535; - public static final int STRIPPED_ACACIA_WOOD = 536; - public static final int STRIPPED_BIRCH_LOG = 537; - public static final int STRIPPED_BIRCH_WOOD = 538; - public static final int STRIPPED_DARK_OAK_LOG = 539; - public static final int STRIPPED_DARK_OAK_WOOD = 540; - public static final int STRIPPED_JUNGLE_LOG = 541; - public static final int STRIPPED_JUNGLE_WOOD = 542; - public static final int STRIPPED_OAK_LOG = 543; - public static final int STRIPPED_OAK_WOOD = 544; - public static final int STRIPPED_SPRUCE_LOG = 545; - public static final int STRIPPED_SPRUCE_WOOD = 546; - public static final int STRUCTURE_BLOCK = 547; - public static final int STRUCTURE_VOID = 548; - public static final int SUGAR_CANE = 549; - public static final int SUNFLOWER = 550; - public static final int SWEET_BERRY_BUSH = 675; - public static final int TALL_GRASS = 551; - public static final int TALL_SEAGRASS = 552; - public static final int TERRACOTTA = 553; - public static final int TNT = 554; - public static final int TORCH = 555; - public static final int TRAPPED_CHEST = 556; - public static final int TRIPWIRE = 557; - public static final int TRIPWIRE_HOOK = 558; - public static final int TUBE_CORAL = 559; - public static final int TUBE_CORAL_BLOCK = 560; - public static final int TUBE_CORAL_FAN = 561; - public static final int TUBE_CORAL_WALL_FAN = 562; - public static final int TURTLE_EGG = 563; - public static final int VINE = 564; - public static final int WALL_TORCH = 566; - public static final int WATER = 567; - public static final int WET_SPONGE = 568; - public static final int WHEAT = 569; - public static final int WHITE_BANNER = 570; - public static final int WHITE_BED = 571; - public static final int WHITE_CARPET = 572; - public static final int WHITE_CONCRETE = 573; - public static final int WHITE_CONCRETE_POWDER = 574; - public static final int WHITE_GLAZED_TERRACOTTA = 575; - public static final int WHITE_SHULKER_BOX = 576; - public static final int WHITE_STAINED_GLASS = 577; - public static final int WHITE_STAINED_GLASS_PANE = 578; - public static final int WHITE_TERRACOTTA = 579; - public static final int WHITE_TULIP = 580; - public static final int WHITE_WALL_BANNER = 581; - public static final int WHITE_WOOL = 582; - public static final int WITHER_ROSE = 676; - public static final int WITHER_SKELETON_SKULL = 583; - public static final int WITHER_SKELETON_WALL_SKULL = 584; - public static final int YELLOW_BANNER = 585; - public static final int YELLOW_BED = 586; - public static final int YELLOW_CARPET = 587; - public static final int YELLOW_CONCRETE = 588; - public static final int YELLOW_CONCRETE_POWDER = 589; - public static final int YELLOW_GLAZED_TERRACOTTA = 590; - public static final int YELLOW_SHULKER_BOX = 591; - public static final int YELLOW_STAINED_GLASS = 592; - public static final int YELLOW_STAINED_GLASS_PANE = 593; - public static final int YELLOW_TERRACOTTA = 594; - public static final int YELLOW_WALL_BANNER = 595; - public static final int YELLOW_WOOL = 596; - public static final int ZOMBIE_HEAD = 597; - public static final int ZOMBIE_WALL_HEAD = 598; - - // Deprecated - public static final int SIGN = OAK_SIGN; - public static final int WALL_SIGN = OAK_WALL_SIGN; - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java index b7d9acace..700070611 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/AsyncPlayer.java @@ -38,7 +38,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public void findFreePosition(Location searchPos) { - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Boolean value) { getBasePlayer().findFreePosition(searchPos); @@ -48,7 +48,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public void setOnGround(Location searchPos) { - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Boolean value) { getBasePlayer().setOnGround(searchPos); @@ -58,7 +58,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public void findFreePosition() { - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Boolean value) { getBasePlayer().findFreePosition(); @@ -68,12 +68,12 @@ public class AsyncPlayer extends PlayerProxy { @Override public boolean ascendLevel() { - return TaskManager.IMP.sync(() -> getBasePlayer().ascendLevel()); + return TaskManager.taskManager().sync(() -> getBasePlayer().ascendLevel()); } @Override public boolean descendLevel() { - return TaskManager.IMP.sync(() -> getBasePlayer().descendLevel()); + return TaskManager.taskManager().sync(() -> getBasePlayer().descendLevel()); } @Override @@ -155,7 +155,7 @@ public class AsyncPlayer extends PlayerProxy { unwrap(getBasePlayer())).build(); edit.setBlock(BlockVector3.at(x, y - 1, z), BlockTypes.GLASS); edit.flushQueue(); - LocalSession session = Fawe.get().getWorldEdit().getSessionManager().get(this); + LocalSession session = Fawe.instance().getWorldEdit().getSessionManager().get(this); if (session != null) { session.remember(edit, true, getBasePlayer().getLimit().MAX_HISTORY); } @@ -173,12 +173,12 @@ public class AsyncPlayer extends PlayerProxy { @Override public void setPosition(Vector3 pos, float pitch, float yaw) { - Fawe.get().getQueueHandler().sync(() -> super.setPosition(pos, pitch, yaw)); + Fawe.instance().getQueueHandler().sync(() -> super.setPosition(pos, pitch, yaw)); } @Override public Location getBlockTrace(int range, boolean useLastBlock) { - return TaskManager.IMP.sync(() -> { + return TaskManager.taskManager().sync(() -> { TargetBlock tb = new TargetBlock(AsyncPlayer.this, range, 0.2D); return useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock(); }); @@ -186,7 +186,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public Location getBlockTraceFace(int range, boolean useLastBlock) { - return TaskManager.IMP.sync(() -> { + return TaskManager.taskManager().sync(() -> { TargetBlock tb = new TargetBlock(AsyncPlayer.this, range, 0.2D); return useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace(); }); @@ -194,7 +194,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public Location getSolidBlockTrace(int range) { - return TaskManager.IMP.sync(() -> { + return TaskManager.taskManager().sync(() -> { TargetBlock tb = new TargetBlock(AsyncPlayer.this, range, 0.2D); return tb.getSolidTargetBlock(); }); @@ -207,7 +207,7 @@ public class AsyncPlayer extends PlayerProxy { @Override public boolean passThroughForwardWall(int range) { - return TaskManager.IMP.sync(() -> { + return TaskManager.taskManager().sync(() -> { int searchDist = 0; TargetBlock hitBlox = new TargetBlock(AsyncPlayer.this, range, 0.2); Extent world = getLocation().getExtent(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java index 8374cba7c..0537aef0a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java @@ -238,7 +238,7 @@ public class WorldWrapper extends AbstractWorld { @Override public void simulateBlockMine(BlockVector3 pt) { - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Object value) { parent.simulateBlockMine(pt); @@ -249,7 +249,7 @@ public class WorldWrapper extends AbstractWorld { //FAWE start @Override public Collection getBlockDrops(final BlockVector3 position) { - return TaskManager.IMP.sync(() -> parent.getBlockDrops(position)); + return TaskManager.taskManager().sync(() -> parent.getBlockDrops(position)); } //FAWE end @@ -266,7 +266,7 @@ public class WorldWrapper extends AbstractWorld { @Override public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { - return TaskManager.IMP.sync(() -> { + return TaskManager.taskManager().sync(() -> { try { return parent.generateTree(type, editSession, position); } catch (MaxChangedBlocksException e) { @@ -307,12 +307,12 @@ public class WorldWrapper extends AbstractWorld { @Override public List getEntities(Region region) { - return TaskManager.IMP.sync(() -> parent.getEntities(region)); + return TaskManager.taskManager().sync(() -> parent.getEntities(region)); } @Override public List getEntities() { - return TaskManager.IMP.sync(parent::getEntities); + return TaskManager.taskManager().sync(parent::getEntities); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 5ac56564b..77757fe77 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -258,47 +258,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Nullable private final Region[] allowedRegions; - @Deprecated(forRemoval = true) - public EditSession( - @Nonnull EventBus bus, World world, @Nullable Player actor, - @Nullable FaweLimit limit, @Nullable AbstractChangeSet changeSet, - @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, - @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, - @Nullable BlockBag blockBag, @Nullable EditSessionEvent event - ) { - this(new EditSessionBuilder(bus).world(world).actor(actor) - .limit(limit) - .changeSet(changeSet) - .allowedRegions(allowedRegions) - .fastMode(fastmode) - .checkMemory(checkMemory) - .combineStages(combineStages) - .blockBag(blockBag) - .event(event)); - } - //FAWE end - - /** - * Construct the object with a maximum number of blocks and a block bag. - * - * @param eventBus the event bus - * @param world the world - * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit - * @param blockBag an optional {@link BlockBag} to use, otherwise null - * @param event the event to call with the extent - */ - //FAWE start - EditSessionEvent - @Deprecated(forRemoval = true) - public EditSession( - @Nonnull EventBus eventBus, - World world, - int maxBlocks, - @Nullable BlockBag blockBag, - EditSessionEvent event - ) { - this(eventBus, world, null, null, null, null, true, null, null, null, blockBag, event); - } - EditSession(EditSessionBuilder builder) { super(builder.compile().getExtent()); this.world = builder.getWorld(); @@ -324,27 +283,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { this.allowedRegions = builder.getAllowedRegions() != null ? builder.getAllowedRegions().clone() : null; } - @Deprecated(forRemoval = true) - public EditSession(com.fastasyncworldedit.core.util.EditSessionBuilder builder) { - super(builder.compile().getExtent()); - this.world = builder.getWorld(); - this.bypassHistory = builder.getBypassHistory(); - this.bypassAll = builder.getBypassAll(); - this.originalLimit = builder.getLimit(); - this.limit = builder.getLimit().copy(); - this.actor = builder.getPlayer(); - this.changeSet = builder.getChangeTask(); - this.minY = world.getMinY(); - this.maxY = world.getMaxY(); - this.blockBag = builder.getBlockBag(); - this.history = changeSet != null; - this.relighter = builder.getRelighter(); - this.wnaMode = builder.isWNAMode(); - this.tracingExtents = null; - - this.allowedRegions = builder.getAllowedRegions() != null ? builder.getAllowedRegions().clone() : null; - } - /** * The limit for this specific edit (blocks etc). * @@ -434,9 +372,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { return output; } - // pkg private for TracedEditSession only, may later become public API - boolean commitRequired() { - //FAWE start + private boolean commitRequired() { + //FAWE start - false for us, returning true if the reorder extent != null for upstream return false; } //FAWE end @@ -1352,7 +1289,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // Don't relight twice! if (!relighter.isFinished() && relighter.getLock().tryLock()) { try { - if (Settings.IMP.LIGHTING.REMOVE_FIRST) { + if (Settings.settings().LIGHTING.REMOVE_FIRST) { relighter.removeAndRelight(true); } else { relighter.fixLightingSafe(true); @@ -1368,14 +1305,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } // Cancel any preloader associated with the actor if present if (getActor() instanceof Player) { - Preloader preloader = Fawe.imp().getPreloader(false); + Preloader preloader = Fawe.platform().getPreloader(false); if (preloader != null) { preloader.cancel(getActor()); } } // Enqueue it if (getChangeSet() != null) { - if (Settings.IMP.HISTORY.COMBINE_STAGES) { + if (Settings.settings().HISTORY.COMBINE_STAGES) { ((AbstractChangeSet) getChangeSet()).closeAsync(); } else { try { @@ -3712,7 +3649,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } if (containsAny) { changes++; - TaskManager.IMP.sync(new RunnableVal() { + TaskManager.taskManager().sync(new RunnableVal() { @Override public void run(Object value) { regenerateChunk(cx, cz, biome, seed); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index 65d92d0f8..11e49f878 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -303,7 +303,7 @@ public final class EditSessionBuilder { */ public EditSessionBuilder changeSet(boolean disk, @Nullable UUID uuid) { if (disk) { - if (Settings.IMP.HISTORY.USE_DATABASE) { + if (Settings.settings().HISTORY.USE_DATABASE) { this.changeSet = new RollbackOptimizedHistory(world, uuid); } else { this.changeSet = new DiskStorageHistory(world, uuid); @@ -377,14 +377,6 @@ public final class EditSessionBuilder { return allowedRegions(new Region[]{RegionWrapper.GLOBAL()}); } - /** - * Does nothing as of 1.13 new queueing system - */ - @Deprecated(forRemoval = true) - public EditSessionBuilder autoQueue(@Nullable Boolean autoQueue) { - return this; - } - /** * Set fast mode. Use null to set to actor's fast mode setting. Also set to true by default if history for console disabled */ @@ -445,7 +437,7 @@ public final class EditSessionBuilder { } if (fastMode == null) { if (actor == null) { - fastMode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; + fastMode = !Settings.settings().HISTORY.ENABLE_FOR_CONSOLE; } else { fastMode = actor.getSession().hasFastMode(); } @@ -474,12 +466,12 @@ public final class EditSessionBuilder { wnaMode = false; if (unwrapped instanceof IQueueExtent) { extent = queue = (IQueueExtent) unwrapped; - } else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) { - ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, fastMode); + } else if (Settings.settings().QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) { + ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, fastMode); queue = parallel.getExtent(); extent = parallel; } else { - extent = queue = Fawe.get().getQueueHandler().getQueue(world); + extent = queue = Fawe.instance().getQueueHandler().getQueue(world); } } else { wnaMode = true; @@ -488,7 +480,7 @@ public final class EditSessionBuilder { if (combineStages == null) { combineStages = // If it's enabled in the settings - Settings.IMP.HISTORY.COMBINE_STAGES + Settings.settings().HISTORY.COMBINE_STAGES // If fast placement is disabled, it's slower to perform a copy on each chunk && this.limit.FAST_PLACEMENT // If the edit uses items from the inventory we can't use a delayed task @@ -498,17 +490,17 @@ public final class EditSessionBuilder { this.bypassHistory = this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER); if (!this.fastMode || changeSet != null) { if (changeSet == null) { - if (Settings.IMP.HISTORY.USE_DISK) { + if (Settings.settings().HISTORY.USE_DISK) { UUID uuid = actor == null ? Identifiable.CONSOLE : actor.getUniqueId(); - if (Settings.IMP.HISTORY.USE_DATABASE) { + if (Settings.settings().HISTORY.USE_DATABASE) { changeSet = new RollbackOptimizedHistory(world, uuid); } else { changeSet = new DiskStorageHistory(world, uuid); } -// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) { +// } else if (combineStages && Settings.settings().HISTORY.COMPRESSION_LEVEL == 0) { // changeSet = new CPUOptimizedChangeSet(world); } else { - if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) { + if (combineStages && Settings.settings().HISTORY.COMPRESSION_LEVEL == 0) { //TODO add CPUOptimizedChangeSet } changeSet = new MemoryOptimizedHistory(world); @@ -536,7 +528,7 @@ public final class EditSessionBuilder { } } } - if (allowedRegions == null && Settings.IMP.REGION_RESTRICTIONS) { + if (allowedRegions == null && Settings.settings().REGION_RESTRICTIONS) { if (actor != null && !actor.hasPermission("fawe.bypass") && !actor.hasPermission("fawe.bypass.regions")) { if (actor instanceof Player) { Player player = (Player) actor; @@ -544,7 +536,7 @@ public final class EditSessionBuilder { } } } - if (disallowedRegions == null && Settings.IMP.REGION_RESTRICTIONS && Settings.IMP.REGION_RESTRICTIONS_OPTIONS.ALLOW_BLACKLISTS) { + if (disallowedRegions == null && Settings.settings().REGION_RESTRICTIONS && Settings.settings().REGION_RESTRICTIONS_OPTIONS.ALLOW_BLACKLISTS) { if (actor != null && !actor.hasPermission("fawe.bypass") && !actor.hasPermission("fawe.bypass.regions")) { if (actor instanceof Player) { Player player = (Player) actor; @@ -570,7 +562,7 @@ public final class EditSessionBuilder { } // There's no need to do lighting (and it'll also just be a pain to implement) if we're not placing chunks if (placeChunks) { - if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.IMP.LIGHTING.MODE > 0))) { + if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.settings().LIGHTING.MODE > 0))) { relighter = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.WORLD_EDITING) .getRelighterFactory().createRelighter(relightMode, world, queue); @@ -712,13 +704,13 @@ public final class EditSessionBuilder { } if (toReturn != extent) { String className = toReturn.getClass().getName().toLowerCase(Locale.ROOT); - for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { + for (String allowed : Settings.settings().EXTENT.ALLOWED_PLUGINS) { if (className.contains(allowed.toLowerCase(Locale.ROOT))) { this.wrapped = true; return toReturn; } } - if (Settings.IMP.EXTENT.DEBUG) { + if (Settings.settings().EXTENT.DEBUG) { if (event.getActor() != null) { event.getActor().printDebug(TextComponent.of("Potentially unsafe extent blocked: " + toReturn .getClass() @@ -730,7 +722,7 @@ public final class EditSessionBuilder { "FAWE config.yml to let FAWE recognize the extent:")); event.getActor().print(toReturn.getClass().getName()); } else { - LOGGER.warn("Potentially unsafe extent blocked: " + toReturn.getClass().getName()); + LOGGER.warn("Potentially unsafe extent blocked: {}", toReturn.getClass().getName()); LOGGER.warn( " - For area restrictions and block logging, it is recommended that third party plugins use the FAWE API"); LOGGER.warn( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index e2dba673b..6d178b363 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -54,7 +54,7 @@ public abstract class LocalConfiguration { private static final Logger LOGGER = LogManagerCompat.getLogger(); public boolean profile = false; - public boolean traceUnflushedSessions = false; + public boolean traceUnflushedSessions = true; public Set disallowedBlocks = new HashSet<>(); protected BlockMask disallowedBlocksMask; public int defaultChangeLimit = -1; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index f0a079e67..236ea7403 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -225,7 +225,7 @@ public class LocalSession implements TextureHolder { if (world == null || uuid == null) { return false; } - if (Settings.IMP.HISTORY.USE_DISK) { + if (Settings.settings().HISTORY.USE_DISK) { MAX_HISTORY_SIZE = Integer.MAX_VALUE; } world = WorldWrapper.unwrap(world); @@ -248,8 +248,8 @@ public class LocalSession implements TextureHolder { private boolean loadHistoryChangeSets(UUID uuid, World world) { SparseBitSet set = new SparseBitSet(); final File folder = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid ); if (folder.isDirectory()) { folder.listFiles(pathname -> { @@ -282,12 +282,12 @@ public class LocalSession implements TextureHolder { } private void loadHistoryNegativeIndex(UUID uuid, World world) { - if (!Settings.IMP.HISTORY.USE_DISK) { + if (!Settings.settings().HISTORY.USE_DISK) { return; } File file = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid + File.separator + "index" + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid + File.separator + "index" ); if (file.exists()) { try (FaweInputStream is = new FaweInputStream(new FileInputStream(file))) { @@ -301,12 +301,12 @@ public class LocalSession implements TextureHolder { } private void saveHistoryNegativeIndex(UUID uuid, World world) { - if (world == null || !Settings.IMP.HISTORY.USE_DISK) { + if (world == null || !Settings.settings().HISTORY.USE_DISK) { return; } File file = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid + File.separator + "index" + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + world.getName() + File.separator + uuid + File.separator + "index" ); if (getHistoryNegativeIndex() != 0) { try { @@ -450,8 +450,8 @@ public class LocalSession implements TextureHolder { } if (o instanceof Integer) { File folder = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HISTORY + File.separator + currentWorld.getName() + File.separator + uuid + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HISTORY + File.separator + currentWorld.getName() + File.separator + uuid ); File specific = new File(folder, o.toString()); if (specific.isDirectory()) { @@ -467,7 +467,7 @@ public class LocalSession implements TextureHolder { public void remember(Identifiable player, World world, ChangeSet changeSet, FaweLimit limit) { historyWriteLock.lock(); try { - if (Settings.IMP.HISTORY.USE_DISK) { + if (Settings.settings().HISTORY.USE_DISK) { LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; } if (changeSet.size() == 0) { @@ -500,7 +500,7 @@ public class LocalSession implements TextureHolder { } if (limit != null) { int limitMb = limit.MAX_HISTORY; - while (((!Settings.IMP.HISTORY.USE_DISK && history.size() > MAX_HISTORY_SIZE) || (historySize >> 20) > limitMb) && history + while (((!Settings.settings().HISTORY.USE_DISK && history.size() > MAX_HISTORY_SIZE) || (historySize >> 20) > limitMb) && history .size() > 1) { ChangeSet item = (ChangeSet) history.remove(0); item.delete(); @@ -516,7 +516,7 @@ public class LocalSession implements TextureHolder { public void remember(EditSession editSession, boolean append, int limitMb) { historyWriteLock.lock(); try { - if (Settings.IMP.HISTORY.USE_DISK) { + if (Settings.settings().HISTORY.USE_DISK) { LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; } // It should have already been flushed, but just in case! @@ -564,7 +564,7 @@ public class LocalSession implements TextureHolder { } else { history.add(0, changeSet); } - while (((!Settings.IMP.HISTORY.USE_DISK && history.size() > MAX_HISTORY_SIZE) || (historySize >> 20) > limitMb) && history + while (((!Settings.settings().HISTORY.USE_DISK && history.size() > MAX_HISTORY_SIZE) || (historySize >> 20) > limitMb) && history .size() > 1) { ChangeSet item = (ChangeSet) history.remove(0); item.delete(); @@ -1146,7 +1146,7 @@ public class LocalSession implements TextureHolder { @Nullable public Tool getTool(Player player) { loadDefaults(player, false); - if (!Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && tools.isEmpty()) { + if (!Settings.settings().EXPERIMENTAL.PERSISTENT_BRUSHES && tools.isEmpty()) { return null; } BaseItem item = player.getItemInHand(HandSide.MAIN_HAND); @@ -1157,7 +1157,7 @@ public class LocalSession implements TextureHolder { public Tool getTool(BaseItem item, Player player) { loadDefaults(player, false); - if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) { + if (Settings.settings().EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) { BrushTool tool = BrushCache.getTool(player, this, item); if (tool != null) { return tool; @@ -1192,13 +1192,13 @@ public class LocalSession implements TextureHolder { /** * Get the brush tool assigned to the item. If there is no tool assigned - * or the tool is not assigned, the slot will be replaced with the + * or the tool is not a brush tool, the slot will be replaced with the * brush tool. * * @param item the item type * @return the tool, or {@code null} * @throws InvalidToolBindException if the item can't be bound to that item - * @deprecated FAWE binds to the item, not the type - this allows brushes to persist + * @deprecated FAWE binds to the item, not the type - this allows brushes to persist, also deprecated in upstream */ @Deprecated public BrushTool getBrushTool(ItemType item) throws InvalidToolBindException { @@ -1232,6 +1232,17 @@ public class LocalSession implements TextureHolder { } //FAWE end + /** + * Get the brush tool assigned to this item. + * + * @param item the item type + * @return the brush tool assigned to the item type + */ + @Nullable + public BrushTool getBrush(ItemType item) { + return getTool(item) instanceof BrushTool tool ? tool : null; + } + //FAWE start - see note of getBrushTool /** @@ -1292,7 +1303,7 @@ public class LocalSession implements TextureHolder { } Tool previous; - if (player != null && (tool instanceof BrushTool || tool == null) && Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) { + if (player != null && (tool instanceof BrushTool || tool == null) && Settings.settings().EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) { previous = BrushCache.getCachedTool(item); BrushCache.setTool(item, (BrushTool) tool); if (tool != null) { @@ -1771,7 +1782,7 @@ public class LocalSession implements TextureHolder { TextureUtil tmp = texture; if (tmp == null) { synchronized (this) { - tmp = Fawe.get().getCachedTextureUtil(true, 0, 100); + tmp = Fawe.instance().getCachedTextureUtil(true, 0, 100); this.texture = tmp; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/TracedEditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/TracedEditSession.java index 586403847..4b4fb860b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/TracedEditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/TracedEditSession.java @@ -21,16 +21,22 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.util.ErrorReporting; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; +import java.lang.ref.Cleaner; /** * Internal use only. Unused for now, but present in case upstream make it API. */ class TracedEditSession extends EditSession { + private static final Cleaner cleaner = Cleaner.create(); + private final TraceRecord record; + private final Cleaner.Cleanable cleanable; + //FAWE start - does not work with FAWE's ways of doing things... @Deprecated //FAWE end @@ -45,22 +51,37 @@ class TracedEditSession extends EditSession { .blockBag(blockBag) .actor(actor) .tracing(tracing)); + this.record = new TraceRecord(actor); + this.cleanable = cleaner.register(this, record); } - TracedEditSession(EditSessionBuilder builder) { - super(builder); + public void close() { + try { + super.close(); + } finally { + this.record.committed = true; + cleanable.clean(); + } } - private final Throwable stacktrace = new Throwable("Creation trace."); + private static final class TraceRecord implements Runnable { + private final Throwable stacktrace = new Throwable("An EditSession was not closed."); + private final Actor actor; - @Override - protected void finalize() throws Throwable { - super.finalize(); + private volatile boolean committed = false; - if (commitRequired()) { - WorldEdit.logger.warn("####### LEFTOVER BUFFER BLOCKS DETECTED #######"); - WorldEdit.logger.warn("This means that some code did not flush their EditSession."); - WorldEdit.logger.warn("Here is a stacktrace from the creation of this EditSession:", stacktrace); + private TraceRecord(Actor actor) { + this.actor = actor; + } + + @Override + public void run() { + if (!committed) { + WorldEdit.logger.warn("####### EDIT SESSION NOT CLOSED #######"); + WorldEdit.logger.warn("This means that some code did not close their EditSession."); + WorldEdit.logger.warn("Here is a stacktrace from the creation of this EditSession:", stacktrace); + ErrorReporting.trigger(actor, stacktrace); + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index d0c338b52..e9a97ab68 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -193,7 +193,7 @@ public class BiomeCommands { player.print(Caption.of( "worldedit.setbiome.changed", - TextComponent.of(visitor.getAffected()) + TextComponent.of(visitor.getAffected() / (editSession.getMaxY() - editSession.getMinY())) )); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index fb38799a1..77cb921cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -59,7 +59,6 @@ import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.util.image.ImageUtil; -import com.fastasyncworldedit.core.world.block.BlockID; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; @@ -861,8 +860,8 @@ public class BrushCommands { } String filenamePng = filename.endsWith(".png") ? filename : filename + ".png"; File file = new File( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.HEIGHTMAP + File.separator + filenamePng + Fawe.platform().getDirectory(), + Settings.settings().PATHS.HEIGHTMAP + File.separator + filenamePng ); if (file.exists()) { return new FileInputStream(file); @@ -937,7 +936,7 @@ public class BrushCommands { if (tool != null) { root |= name.startsWith("../"); name = FileSystems.getDefault().getPath(name).getFileName().toString(); - File folder = MainUtil.getFile(Fawe.imp().getDirectory(), "brushes"); + File folder = MainUtil.getFile(Fawe.platform().getDirectory(), "brushes"); name = name.endsWith(".jsgz") ? name : name + ".jsgz"; File file; if (root && player.hasPermission("worldedit.brush.save.other")) { @@ -972,7 +971,7 @@ public class BrushCommands { public void loadBrush(Player player, LocalSession session, @Arg(desc = "String name") String name) throws WorldEditException, IOException { name = FileSystems.getDefault().getPath(name).getFileName().toString(); - File folder = MainUtil.getFile(Fawe.imp().getDirectory(), "brushes"); + File folder = MainUtil.getFile(Fawe.platform().getDirectory(), "brushes"); name = name.endsWith(".jsgz") ? name : name + ".jsgz"; File file = new File(folder, player.getUniqueId() + File.separator + name); if (!file.exists()) { @@ -1007,7 +1006,7 @@ public class BrushCommands { int page ) throws WorldEditException { String baseCmd = "/brush loadbrush"; - File dir = MainUtil.getFile(Fawe.imp().getDirectory(), "brushes"); + File dir = MainUtil.getFile(Fawe.platform().getDirectory(), "brushes"); // TODO NOT IMPLEMENTED // UtilityCommands.list(dir, actor, args, page, null, true, baseCmd); } @@ -1187,9 +1186,9 @@ public class BrushCommands { //FAWE start - Suggest different brush material if sand or gravel is used if (pattern instanceof BlockStateHolder) { BlockType type = ((BlockStateHolder) pattern).getBlockType(); - switch (type.getInternalId()) { - case BlockID.SAND: - case BlockID.GRAVEL: + switch (type.getId()) { + case "minecraft:sand": + case "minecraft:gravel": player.print( Caption.of("fawe.worldedit.brush.brush.try.other")); falling = true; @@ -1311,7 +1310,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(radius); //FAWE start - FaweLimit limit = Settings.IMP.getLimit(player); + FaweLimit limit = Settings.settings().getLimit(player); iterations = Math.min(limit.MAX_ITERATIONS, iterations); //FAWE end @@ -1346,7 +1345,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(radius); //FAWE start - FaweLimit limit = Settings.IMP.getLimit(player); + FaweLimit limit = Settings.settings().getLimit(player); iterations = Math.min(limit.MAX_ITERATIONS, iterations); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 61c220f68..f3a24ed9c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -405,7 +405,7 @@ public class ClipboardCommands { url = null; } } else { - if (Settings.IMP.WEB.URL.isEmpty()) { + if (Settings.settings().WEB.URL.isEmpty()) { actor.print(Caption.of("fawe.error.setting.disable", "web.url")); return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index c7bcc7e65..3d54e40a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -475,7 +475,7 @@ public class GeneralCommands { String arg = arguments.get(0); String argLower = arg.toLowerCase(Locale.ROOT); - TextureUtil util = Fawe.get().getTextureUtil(); + TextureUtil util = Fawe.instance().getTextureUtil(); int randomIndex = 1; boolean checkRandomization = true; if (arguments.size() >= 2 && MathMan.isInteger(arguments.get(0)) && MathMan.isInteger(arguments.get(1))) { @@ -500,7 +500,7 @@ public class GeneralCommands { Clipboard clipboard = session.getClipboard().getClipboard(); util = TextureUtil.fromClipboard(clipboard); } else if (argLower.equals("*") || argLower.equals("true")) { - util = Fawe.get().getTextureUtil(); + util = Fawe.instance().getTextureUtil(); } else { ParserContext parserContext = new ParserContext(); parserContext.setActor(actor); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index d63f26e52..b34e7860f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -582,7 +582,7 @@ public class GenerationCommands { @Arg(desc = "TODO", def = "100") int threshold, @Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions ) throws WorldEditException, IOException { - TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold); + TextureUtil tu = Fawe.instance().getCachedTextureUtil(randomize, 0, threshold); URL url = new URL(imageURL); if (!url.getHost().equalsIgnoreCase("i.imgur.com")) { throw new IOException("Only i.imgur.com links are allowed!"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 1d97c13d2..3688041d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -114,7 +114,7 @@ public class HistorySubCommands { @Switch(name = 'f', desc = "Restore instead of rollback") boolean restore ) throws WorldEditException { - if (!Settings.IMP.HISTORY.USE_DATABASE) { + if (!Settings.settings().HISTORY.USE_DATABASE) { player.print(Caption.of("fawe.error.setting.disable", "history.use-database (Import with /history import )")); return; } @@ -168,7 +168,7 @@ public class HistorySubCommands { @CommandPermissions("fawe.rollback.import") @Confirm public synchronized void importdb(Actor actor) throws WorldEditException { - File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY); + File folder = MainUtil.getFile(Fawe.platform().getDirectory(), Settings.settings().PATHS.HISTORY); if (folder.exists()) { for (File worldFolder : Objects.requireNonNull(folder.listFiles())) { if (worldFolder != null && worldFolder.isDirectory()) { @@ -238,7 +238,7 @@ public class HistorySubCommands { } Location origin = player.getLocation(); - String name = Fawe.imp().getName(edit.getUUID()); + String name = Fawe.platform().getName(edit.getUUID()); String cmd = edit.getCommand(); BlockVector3 pos1 = edit.getMinimumPoint(); BlockVector3 pos2 = edit.getMaximumPoint(); @@ -319,7 +319,7 @@ public class HistorySubCommands { UUID uuid = rollback.getUUID(); int index = rollback.getIndex(); - String name = Fawe.imp().getName(rollback.getUUID()); + String name = Fawe.platform().getName(rollback.getUUID()); String cmd = rollback.getCommand(); BlockVector3 pos1 = rollback.getMinimumPoint(); @@ -382,7 +382,7 @@ public class HistorySubCommands { @ArgFlag(name = 'p', desc = "Page to view.", def = "") Integer page ) throws WorldEditException { - if (!Settings.IMP.HISTORY.USE_DATABASE) { + if (!Settings.settings().HISTORY.USE_DATABASE) { player.print(Caption.of("fawe.error.setting.disable", "history.use-database (Import with //history import )")); return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 6e7f5f4fd..4065c56ad 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -203,7 +203,7 @@ public class SchematicCommands { } else { final LocalConfiguration config = this.worldEdit.getConfiguration(); File working = this.worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); - File root = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; + File root = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; uri = new File(root, fileName).toURI(); } @@ -238,13 +238,13 @@ public class SchematicCommands { IOException { LocalConfiguration config = worldEdit.getConfiguration(); File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); - File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; + File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; File destDir = new File(dir, directory); if (!MainUtil.isInSubDirectory(working, destDir)) { actor.print(Caption.of("worldedit.schematic.directory-does-not-exist", TextComponent.of(String.valueOf(destDir)))); return; } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, destDir) && !actor.hasPermission( + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, destDir) && !actor.hasPermission( "worldedit.schematic.move.other")) { actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.move.other")); return; @@ -265,7 +265,7 @@ public class SchematicCommands { actor.print(Caption.of("fawe.worldedit.schematic.schematic.move.exists", destFile)); continue; } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && (!MainUtil.isInSubDirectory( + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && (!MainUtil.isInSubDirectory( dir, destFile ) || !MainUtil.isInSubDirectory(dir, source)) && !actor.hasPermission("worldedit.schematic.delete.other")) { @@ -333,7 +333,7 @@ public class SchematicCommands { return; } UUID uuid = UUID.fromString(filename.substring(4)); - URL webUrl = new URL(Settings.IMP.WEB.URL); + URL webUrl = new URL(Settings.settings().WEB.URL); format = ClipboardFormats.findByAlias(formatName); URL url = new URL(webUrl, "uploads/" + uuid + "." + format.getPrimaryFileExtension()); ReadableByteChannel byteChannel = Channels.newChannel(url.openStream()); @@ -341,7 +341,7 @@ public class SchematicCommands { uri = url.toURI(); } else { File saveDir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); - File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(saveDir, actor.getUniqueId().toString()) : saveDir; + File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(saveDir, actor.getUniqueId().toString()) : saveDir; File file; if (filename.startsWith("#")) { format = ClipboardFormats.findByAlias(formatName); @@ -357,7 +357,7 @@ public class SchematicCommands { return; } } else { - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !actor.hasPermission("worldedit.schematic.load.other") && Pattern + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !actor.hasPermission("worldedit.schematic.load.other") && Pattern .compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") .matcher(filename) .find()) { @@ -446,7 +446,7 @@ public class SchematicCommands { File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); //FAWE start - if (!global && Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS) { + if (!global && Settings.settings().PATHS.PER_PLAYER_SCHEMATICS) { dir = new File(dir, actor.getUniqueId().toString()); } @@ -580,7 +580,7 @@ public class SchematicCommands { final boolean hasShow = false; //If player forgot -p argument - boolean playerFolder = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS; + boolean playerFolder = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS; UUID uuid = playerFolder ? actor.getUniqueId() : null; List files = UtilityCommands.getFiles(dir, actor, args, formatName, playerFolder, oldFirst, newFirst); List> entries = UtilityCommands.filesToEntry(dir, files, uuid); @@ -670,14 +670,14 @@ public class SchematicCommands { String headerBytesElem = String.format("%.1fkb", totalBytes / 1000.0); - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) { headerBytesElem += String.format( " / %dkb", - Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT + Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT ); } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS) { String fullHeader = "| My Schematics: " + headerBytesElem + " |"; PaginationBox paginationBox = PaginationBox.fromComponents(fullHeader, pageCommand, components); actor.print(paginationBox.create(page)); @@ -704,7 +704,7 @@ public class SchematicCommands { LocalConfiguration config = worldEdit.getConfiguration(); File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); //FAWE start - File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; + File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working; List files = new ArrayList<>(); if (filename.equalsIgnoreCase("*")) { @@ -723,7 +723,7 @@ public class SchematicCommands { actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename))); continue; } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission( + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission( "worldedit.schematic.delete.other")) { actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.delete.other")); continue; @@ -806,8 +806,8 @@ public class SchematicCommands { Clipboard target; //FAWE start - boolean checkFilesize = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS - && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1; + boolean checkFilesize = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS + && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1; double directorysizeKb = 0; String curFilepath = file.getAbsolutePath(); @@ -838,7 +838,7 @@ public class SchematicCommands { } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { if (numFiles == -1) { numFiles = 0; @@ -851,7 +851,7 @@ public class SchematicCommands { } } } - int limit = Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT; + int limit = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT; if (numFiles >= limit) { TextComponent noSlotsErr = TextComponent.of( //TODO - to be moved into captions/translatablecomponents @@ -902,7 +902,7 @@ public class SchematicCommands { if (checkFilesize) { double curKb = filesizeKb + directorysizeKb; - int allocatedKb = Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT; + int allocatedKb = Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT; if (overwrite) { curKb -= oldKbOverwritten; @@ -937,11 +937,11 @@ public class SchematicCommands { actor.print(kbRemainingNotif); } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) { TextComponent slotsRemainingNotif = TextComponent.of( //TODO - to be moved into captions/translatablecomponents - "You have " + (Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT - numFiles) + "You have " + (Settings.settings().EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT - numFiles) + " schematic file slots left.", TextColor.GRAY ); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 4dbbc29dc..1037df0b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -25,6 +25,7 @@ import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.function.QuadFunction; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MaskTraverser; +import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.image.ImageUtil; import com.fastasyncworldedit.core.util.task.DelegateConsumer; @@ -135,9 +136,9 @@ public class UtilityCommands { @Arg(name = "max", desc = "int", def = "200") int max ) throws IOException { actor.print(TextComponent.of("Please wait while we generate the minified heightmaps.")); - File srcFolder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HEIGHTMAP); + File srcFolder = MainUtil.getFile(Fawe.platform().getDirectory(), Settings.settings().PATHS.HEIGHTMAP); - File webSrc = new File(Fawe.imp().getDirectory(), "web" + File.separator + "heightmap"); + File webSrc = new File(Fawe.platform().getDirectory(), "web" + File.separator + "heightmap"); File minImages = new File(webSrc, "images" + File.separator + "min"); File maxImages = new File(webSrc, "images" + File.separator + "max"); final int sub = srcFolder.getAbsolutePath().length(); @@ -698,7 +699,7 @@ public class UtilityCommands { //FAWE start - run this sync int finalRadius = radius; - int killed = TaskManager.IMP.sync(() -> killMatchingEntities(finalRadius, actor, flags::createFunction)); + int killed = TaskManager.taskManager().sync(() -> killMatchingEntities(finalRadius, actor, flags::createFunction)); //FAWE end actor.print(Caption.of( @@ -730,7 +731,7 @@ public class UtilityCommands { } //FAWE start - run this sync - int removed = TaskManager.IMP.sync(() -> killMatchingEntities(radius, actor, remover::createFunction)); + int removed = TaskManager.taskManager().sync(() -> killMatchingEntities(radius, actor, remover::createFunction)); //FAWE end actor.print(Caption.of("worldedit.remove.removed", TextComponent.of(removed))); return removed; @@ -876,8 +877,7 @@ public class UtilityCommands { } try { if (!MainUtil.isInSubDirectory(root, file)) { - throw new RuntimeException( - new StopExecutionException(TextComponent.of("Invalid path"))); + throw new StopExecutionException(TextComponent.of("Invalid path")); } } catch (IOException ignored) { } @@ -953,7 +953,7 @@ public class UtilityCommands { String dirFilter = File.separator; boolean listMine = false; - boolean listGlobal = !Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS; + boolean listGlobal = !Settings.settings().PATHS.PER_PLAYER_SCHEMATICS; if (len > 0) { for (String arg : args) { switch (arg.toLowerCase(Locale.ROOT)) { @@ -982,7 +982,7 @@ public class UtilityCommands { if (!exists) { arg = arg.substring(0, arg.length() - File.separator.length()); if (arg.length() > 3 && arg.length() <= 16) { - UUID fromName = Fawe.imp().getUUID(arg); + UUID fromName = Fawe.platform().getUUID(arg); if (fromName != null) { newDirFilter = dirFilter + fromName + File.separator; listGlobal = true; @@ -1034,7 +1034,27 @@ public class UtilityCommands { if (playerFolder) { if (listMine) { File playerDir = MainUtil.resolveRelative(new File(dir, actor.getUniqueId() + dirFilter)); + //FAWE start - Schematic list other permission + if (!actor.hasPermission("worldedit.schematic.list.other") && StringMan.containsUuid(dirFilter)) { + return; + } if (playerDir.exists()) { + if (!actor.hasPermission("worldedit.schematic.list.other")) { + forEachFile = new DelegateConsumer<>(forEachFile) { + @Override + public void accept(File f) { + try { + if (f.isDirectory() && !UUID.fromString(f.getName()).equals(actor.getUniqueId())) { // Ignore + // directories of other players + return; + } + } catch (IllegalArgumentException ignored) { + } + super.accept(f); + } + }; + } + //FAWE end allFiles(playerDir.listFiles(), false, forEachFile); } } @@ -1103,7 +1123,7 @@ public class UtilityCommands { if (newList.isEmpty()) { String checkName = filter.replace("\\", "/").split("/")[0]; if (checkName.length() > 3 && checkName.length() <= 16) { - UUID fromName = Fawe.imp().getUUID(checkName); + UUID fromName = Fawe.platform().getUUID(checkName); if (fromName != null) { lowerFilter = filter.replaceFirst(checkName, fromName.toString()).toLowerCase(Locale.ROOT); for (int i = 0; i < normalizedNames.length; i++) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 2c767fad2..4a5883b90 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -80,52 +80,17 @@ public class WorldEditCommands { ) @CommandPermissions(queued = false) public void version(Actor actor) { - //FAWE start - get own version format - FaweVersion fVer = Fawe.get().getVersion(); + //FAWE start - use own, minimized message that doesn't print "Platforms" and "Capabilities" + FaweVersion fVer = Fawe.instance().getVersion(); String fVerStr = fVer == null ? "unknown" : "-" + fVer.build; - actor.print(TextComponent.of("FastAsyncWorldEdit" + fVerStr + " created by Empire92, MattBDev, IronApollo, dordsor21 and NotMyFault")); - - if (fVer != null) { - FaweVersion version = Fawe.get().getVersion(); - Date date = new GregorianCalendar(2000 + version.year, version.month - 1, version.day) - .getTime(); - - TextComponent dateArg = TextComponent.of(date.toLocaleString()); - TextComponent commitArg = TextComponent.of(Integer.toHexString(version.hash)); - TextComponent buildArg = TextComponent.of(version.build); - TextComponent platformArg = TextComponent.of(Settings.IMP.PLATFORM); - - actor.print(Caption.of("worldedit.version.version", dateArg, commitArg, buildArg, platformArg)); - } - - actor.printInfo(TextComponent.of("Wiki: https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki")); + actor.print(TextComponent.of("FastAsyncWorldEdit" + fVerStr)); + actor.print(TextComponent.of("Authors: Empire92, MattBDev, IronApollo, dordsor21 and NotMyFault")); + actor.print(TextComponent.of("Wiki: https://git.io/JMEPa") + .clickEvent(ClickEvent.openUrl("https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki"))); + actor.print(TextComponent.of("Discord: https://discord.gg/intellectualsites") + .clickEvent(ClickEvent.openUrl("https://discord.gg/intellectualsites"))); UpdateNotification.doUpdateNotification(actor); //FAWE end - - PlatformManager pm = we.getPlatformManager(); - - TextComponentProducer producer = new TextComponentProducer(); - for (Platform platform : pm.getPlatforms()) { - producer.append( - TextComponent.of("* ", TextColor.GRAY) - .append(TextComponent.of(platform.getPlatformName()) - .hoverEvent(HoverEvent.showText(TextComponent.of(platform.getId())))) - .append(TextComponent.of("(" + platform.getPlatformVersion() + ")")) - ).newline(); - } - actor.print(new MessageBox("Platforms", producer, TextColor.GRAY).create()); - - producer.reset(); - for (Capability capability : Capability.values()) { - Platform platform = pm.queryCapability(capability); - producer.append( - TextComponent.of(capability.name(), TextColor.GRAY) - .append(TextComponent.of(": ") - .append(TextComponent.of(platform != null ? platform.getPlatformName() : "none"))) - ).newline(); - } - actor.print(new MessageBox("Capabilities", producer, TextColor.GRAY).create()); - } @Command( @@ -140,7 +105,7 @@ public class WorldEditCommands { .queryCapability(Capability.CONFIGURATION) .getConfiguration())); //FAWE start - Fawe.get().setupConfigs(); + Fawe.instance().setupConfigs(); //FAWE end actor.print(Caption.of("worldedit.reload.config")); } @@ -148,16 +113,16 @@ public class WorldEditCommands { //FAWE start @Command( name = "debugpaste", - desc = "Writes a report of latest.log, config.yml, config-legacy.yml, strings.json to https://athion.net/ISPaster/paste" + desc = "Writes a report of latest.log, config.yml, worldedit-config.yml, strings.json to https://athion.net/ISPaster/paste" ) @CommandPermissions(value = {"worldedit.report", "worldedit.debugpaste"}, queued = false) public void report(Actor actor) throws WorldEditException { String dest; try { final File logFile = new File("logs/latest.log"); - final File config = new File(Fawe.imp().getDirectory(), "config.yml"); - final File legacyConfig = new File(Fawe.imp().getDirectory(), "config-legacy.yml"); - dest = IncendoPaster.debugPaste(logFile, Fawe.imp().getDebugInfo(), config, legacyConfig); + final File config = new File(Fawe.platform().getDirectory(), "config.yml"); + final File worldeditConfig = new File(Fawe.platform().getDirectory(), "worldedit-config.yml"); + dest = IncendoPaster.debugPaste(logFile, Fawe.platform().getDebugInfo(), config, worldeditConfig); } catch (IOException e) { actor.printInfo(TextComponent.of(e.getMessage())); return; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java index d2a6fde14..23e570107 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.command.tool; import com.fastasyncworldedit.core.configuration.Caption; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.entity.Player; @@ -56,9 +55,8 @@ public class QueryTool implements BlockTool { ) { World world = (World) clicked.getExtent(); - EditSession editSession = session.createEditSession(player); BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); - BaseBlock block = editSession.getFullBlock(blockPoint); + BaseBlock block = world.getFullBlock(blockPoint); TextComponent.Builder builder = TextComponent.builder(); builder.append(TextComponent.of("@" + clicked.toVector().toBlockPoint() + ": ", TextColor.BLUE)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java index f1e8c2e04..79bd7be24 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java @@ -56,7 +56,7 @@ public enum SelectionWand implements DoubleActionBlockTool { if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { //FAWE start - if (Settings.IMP.EXPERIMENTAL.OTHER) { + if (Settings.settings().EXPERIMENTAL.OTHER) { LOGGER.info("actSecondary Hit and about to explain with explainPrimarySelection"); } //FAWE end @@ -79,7 +79,7 @@ public enum SelectionWand implements DoubleActionBlockTool { if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { //FAWE start - if (Settings.IMP.EXPERIMENTAL.OTHER) { + if (Settings.settings().EXPERIMENTAL.OTHER) { LOGGER.info("actPrimary Hit and about to explain with explainSecondarySelection"); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java index 023b33672..f2310a211 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java @@ -148,7 +148,7 @@ public class EntityRemover { if (registryType != null) { if (type.matches(registryType)) { //FAWE start - Calling this async violates thread safety - TaskManager.IMP.sync(entity::remove); + TaskManager.taskManager().sync(entity::remove); //FAWE end return true; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java index eeb5989f2..5bf1ccc6c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/ConfirmHandler.java @@ -29,7 +29,7 @@ public class ConfirmHandler implements CommandCallListener { } Actor actor = actorOpt.get(); // don't check confirmation if actor doesn't need to confirm - if (!Settings.IMP.getLimit(actor).CONFIRM_LARGE) { + if (!Settings.settings().getLimit(actor).CONFIRM_LARGE) { return; } if (!confirmAnnotation.value().passes(actor, parameters, 1)) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Preload.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Preload.java index 3c1104321..ae05397bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Preload.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/Preload.java @@ -32,7 +32,7 @@ public @interface Preload { @Override public void preload(Actor actor, InjectedValueAccess context) { World world = context.injectedValue(Key.of(EditSession.class)).get().getWorld(); - Preloader preloader = Fawe.imp().getPreloader(true); + Preloader preloader = Fawe.platform().getPreloader(true); if (preloader != null) { preloader.update(actor, world); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java index 034101537..9e1dc106f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/annotation/PreloadHandler.java @@ -29,7 +29,7 @@ public class PreloadHandler implements CommandCallListener { } Actor actor = actorOpt.get(); // Don't attempt to preload if effectively disabled - if (Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT <= 1) { + if (Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT <= 1) { return; } preloadAnnotation.value().preload(actor, parameters); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 09b82b028..33ea8bae4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -425,7 +425,7 @@ public interface Player extends Entity, Actor { default void unregister() { cancel(true); LocalSession session = getSession(); - if (Settings.IMP.CLIPBOARD.USE_DISK && Settings.IMP.CLIPBOARD.DELETE_ON_LOGOUT) { + if (Settings.settings().CLIPBOARD.USE_DISK && Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { ClipboardHolder holder = session.getExistingClipboard(); if (holder != null) { for (Clipboard clipboard : holder.getClipboards()) { @@ -443,10 +443,10 @@ public interface Player extends Entity, Actor { }); } } - } else if (Settings.IMP.CLIPBOARD.DELETE_ON_LOGOUT || Settings.IMP.CLIPBOARD.USE_DISK) { + } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT || Settings.settings().CLIPBOARD.USE_DISK) { WorldEdit.getInstance().getExecutorService().submit(() -> session.setClipboard(null)); } - if (Settings.IMP.HISTORY.DELETE_ON_LOGOUT) { + if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) { session.clearHistory(); } } @@ -458,8 +458,8 @@ public interface Player extends Entity, Actor { */ default void loadClipboardFromDisk() { File file = MainUtil.getFile( - Fawe.imp().getDirectory(), - Settings.IMP.PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd" + Fawe.platform().getDirectory(), + Settings.settings().PATHS.CLIPBOARD + File.separator + getUniqueId() + ".bd" ); try { if (file.exists() && file.length() > 5) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java index e1f6cdca1..cf3f7d753 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java @@ -21,8 +21,10 @@ package com.sk89q.worldedit.extension.input; import com.fastasyncworldedit.core.configuration.Caption; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.MaskFactory; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.World; @@ -303,8 +305,8 @@ public class ParserContext { minY = extent.getMinY(); maxY = extent.getMaxY(); } else { - minY = 0; - maxY = 255; + minY = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(); + maxY = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(); } return minY; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java index 1edad0ba1..0b8909198 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java @@ -110,7 +110,7 @@ public abstract class AbstractNonPlayerActor implements Actor { if (async) { asyncNotifyQueue.run(wrapped); } else { - TaskManager.IMP.taskNow(wrapped, false); + TaskManager.taskManager().taskNow(wrapped, false); } return true; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 87d137283..d02819dc6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -491,7 +491,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Region[] getAllowedRegions(FaweMaskManager.MaskType type) { - return WEManager.IMP.getMask(this, type, true); + return WEManager.weManager().getMask(this, type, true); } @Override @@ -501,7 +501,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Region[] getDisallowedRegions(FaweMaskManager.MaskType type) { - return WEManager.IMP.getMask(this, type, false); + return WEManager.weManager().getMask(this, type, false); } @Override @@ -677,7 +677,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { if (async) { asyncNotifyQueue.run(wrapped); } else { - TaskManager.IMP.taskNow(wrapped, false); + TaskManager.taskManager().taskNow(wrapped, false); } return true; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index 1f938ea82..a2871270b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -220,13 +220,13 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab default boolean checkAction() { long time = getMeta("faweActionTick", Long.MIN_VALUE); - long tick = Fawe.get().getTimer().getTick(); + long tick = Fawe.instance().getTimer().getTick(); setMeta("faweActionTick", tick); return tick > time; } default FaweLimit getLimit() { - return Settings.IMP.getLimit(this); + return Settings.settings().getLimit(this); } default boolean runAsyncIfFree(Runnable r) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index abb84c3fe..fc53e5d44 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.extension.platform; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.registry.Keyed; @@ -235,5 +236,17 @@ public interface Platform extends Keyed { */ @Nonnull RelighterFactory getRelighterFactory(); + + /** + * Get the default minimum Y value of worlds based on Minecraft version (inclusive). + * @since 2.0.0 + */ + int versionMinY(); + + /** + * Get the default maximum Y value of worlds based on Minecraft version (inclusive). + * @since 2.0.0 + */ + int versionMaxY(); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index d07b4d805..4c23e353d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -120,6 +120,7 @@ import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter; +import com.sk89q.worldedit.internal.util.ErrorReporting; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.regions.Region; @@ -433,7 +434,7 @@ public final class PlatformCommandManager { public void registerAllCommands() { //FAWE start - if (Settings.IMP.ENABLED_COMPONENTS.COMMANDS) { + if (Settings.settings().ENABLED_COMPONENTS.COMMANDS) { // TODO: Ping @MattBDev to reimplement (or remove) 2020-02-04 // registerSubCommands( // "patterns", @@ -673,7 +674,7 @@ public final class PlatformCommandManager { Actor actor = event.getActor(); String args = event.getArguments(); - TaskManager.IMP.taskNow(() -> { + TaskManager.taskManager().taskNow(() -> { if (!Fawe.isMainThread()) { Thread.currentThread().setName("FAWE Thread for player: " + actor.getName()); } @@ -884,10 +885,9 @@ public final class PlatformCommandManager { } private void handleUnknownException(Actor actor, Throwable t) { - actor.print(Caption.of("worldedit.command.error.report")); - actor.print(TextComponent.of(t.getClass().getName() + ": " + t.getMessage())); //FAWE start - Exchange name LOGGER.error("An unexpected error while handling a FastAsyncWorldEdit command", t); + ErrorReporting.trigger(actor, t); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index a29903a6d..d3944a153 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -244,7 +244,7 @@ public class AbstractDelegateExtent implements Extent { @Override public Extent addProcessor(IBatchProcessor processor) { - if (Settings.IMP.EXPERIMENTAL.OTHER) { + if (Settings.settings().EXPERIMENTAL.OTHER) { LOGGER.info("addProcessor Info: \t " + processor.getClass().getName()); LOGGER.info("The following is not an error or a crash:"); StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); @@ -262,7 +262,7 @@ public class AbstractDelegateExtent implements Extent { @Override public Extent addPostProcessor(IBatchProcessor processor) { - if (Settings.IMP.EXPERIMENTAL.OTHER) { + if (Settings.settings().EXPERIMENTAL.OTHER) { LOGGER.info("addPostProcessor Info: \t " + processor.getClass().getName()); LOGGER.info("The following is not an error or a crash:"); StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 9d4fa8dfd..334ab4da4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -870,7 +870,7 @@ public interface Extent extends InputExtent, OutputExtent { } default Extent enableHistory(AbstractChangeSet changeSet) { - if (Settings.IMP.HISTORY.SEND_BEFORE_HISTORY) { + if (Settings.settings().HISTORY.SEND_BEFORE_HISTORY) { return addPostProcessor(changeSet); } else { return addProcessor(changeSet); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java index 345ff978f..c28f4a07a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/MaskingExtent.java @@ -62,7 +62,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce checkNotNull(mask); this.mask = mask; //FAWE start - this.threadIdToFilter = FaweCache.IMP.createCache(() -> new CharFilterBlock(getExtent())); + this.threadIdToFilter = FaweCache.INSTANCE.createCache(() -> new CharFilterBlock(getExtent())); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index ffe880557..d90bce937 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -22,7 +22,9 @@ package com.sk89q.worldedit.extent; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; @@ -95,7 +97,9 @@ public interface OutputExtent { @Deprecated default boolean setBiome(BlockVector2 position, BiomeType biome) { boolean result = false; - for (int y = 0; y < 256; y++) { + int minY = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(); + int maxY = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(); + for (int y = minY; y < maxY; y++) { result |= setBiome(position.toBlockVector3().mutY(y), biome); } return result; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index 241425a8e..c4d940d7a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -70,6 +70,10 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl //FAWE end //FAWE start + + /** + * Creates a new {@link ReadOnlyClipboard}. + */ static Clipboard create(Region region) { checkNotNull(region); checkNotNull( @@ -85,10 +89,17 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl return ReadOnlyClipboard.of(session, region); } + /** + * Create a new {@link com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard} instance. + * Will be one of the following, depending on settings: + * - {@link DiskOptimizedClipboard} + * - {@link CPUOptimizedClipboard} + * - {@link MemoryOptimizedClipboard} + */ static Clipboard create(Region region, UUID uuid) { - if (Settings.IMP.CLIPBOARD.USE_DISK) { + if (Settings.settings().CLIPBOARD.USE_DISK) { return new DiskOptimizedClipboard(region, uuid); - } else if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL == 0) { + } else if (Settings.settings().CLIPBOARD.COMPRESSION_LEVEL == 0) { return new CPUOptimizedClipboard(region); } else { return new MemoryOptimizedClipboard(region); @@ -249,7 +260,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl */ default EditSession paste( World world, BlockVector3 to, boolean allowUndo, boolean pasteAir, - boolean copyEntities, @Nullable Transform transform + boolean pasteEntities, @Nullable Transform transform ) { checkNotNull(world); checkNotNull(to); @@ -275,7 +286,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl if (transform != null && !transform.isIdentity()) { extent = new BlockTransformExtent(this, transform); } else if (sourceMask == null) { - paste(editSession, to, pasteAir); + paste(editSession, to, pasteAir, pasteEntities, hasBiomes()); editSession.flushQueue(); return editSession; } @@ -285,7 +296,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl if (transform != null && !transform.isIdentity()) { copy.setTransform(transform); } - copy.setCopyingEntities(copyEntities); + copy.setCopyingEntities(pasteEntities); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(extent); copy.setSourceMask(sourceMask); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 70e6d4161..b00c9ea5b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -187,21 +187,21 @@ public class ClipboardFormats { } return null; } - URL base = new URL(Settings.IMP.WEB.URL); + URL base = new URL(Settings.settings().WEB.URL); input = new URL(base, "uploads/" + input.substring(4) + "." + format.getPrimaryFileExtension()).toString(); } if (input.startsWith("http")) { return null; } - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) { player.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other")); return null; } File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile(); - File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS + File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; File f; if (input.startsWith("#")) { @@ -219,7 +219,7 @@ public class ClipboardFormats { return null; } } else { - if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS + if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) { if (message) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index 2c743fd74..760598ad5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -206,7 +206,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { //FAWE start - tile entity safety - perhaps caused by the old issue with tile entities created in the wrong // position in schematics? if (index >= blocks.length) { - LOGGER.warn("Skipping corrupt tile entity at position " + x + " " + y + " " + z + " in schematic."); + LOGGER.warn("Skipping corrupt tile entity at position {} {} {} in schematic.", x, y, z); continue; } @@ -275,8 +275,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { byte data = blockData[index]; int combined = block << 8 | data; if (unknownBlocks.add(combined)) { - LOGGER.warn("Unknown block when loading schematic: " - + block + ":" + data + ". This is most likely a bad schematic."); + LOGGER.warn("Unknown block when loading schematic: {} {}. This is most likely a" + + "bad schematic.", block, data); } } } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java index 7a379d622..2a10e9f4b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java @@ -120,7 +120,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { metadata.put("WEOffsetX", new IntTag(offset.getBlockX())); metadata.put("WEOffsetY", new IntTag(offset.getBlockY())); metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ())); - metadata.put("FAWEVersion", new IntTag(Fawe.get().getVersion().build)); + metadata.put("FAWEVersion", new IntTag(Fawe.instance().getVersion().build)); schematic.put("Metadata", new CompoundTag(metadata)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 674ac46e6..8382319c9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -438,7 +438,7 @@ public class BlockTransformExtent extends ResettableExtent { if (directions != null) { int oldIndex = property.getIndex(state.getInternalId()); if (oldIndex >= directions.length) { - if (Settings.IMP.ENABLED_COMPONENTS.DEBUG) { + if (Settings.settings().ENABLED_COMPONENTS.DEBUG) { LOGGER.warn(String.format( "Index outside direction array length found for block:{%s} property:{%s}", state.getBlockType().getId(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java index c061b0b35..88cf4fc6f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -99,7 +99,7 @@ public class SurvivalModeExtent extends AbstractDelegateExtent { Collection drops = world.getBlockDrops(location); boolean canSet = super.setBlock(location, block); if (canSet) { - TaskManager.IMP.sync(new RunnableVal<>() { + TaskManager.taskManager().sync(new RunnableVal<>() { @Override public void run(Object value) { for (BaseItemStack stack : drops) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java index d199fcb61..5ea9aa66e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java @@ -20,10 +20,13 @@ package com.sk89q.worldedit.function.generator; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; +import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -40,6 +43,11 @@ public class FloraGenerator implements RegionFunction { private final boolean biomeAware = false; private final Pattern desertPattern = getDesertPattern(); private final Pattern temperatePattern = getTemperatePattern(); + //FAWE start + private final Pattern mushroomPattern = mushroomPattern(); + private final Pattern netherPattern = netherPattern(); + private final Pattern warpedNyliumPattern = warpedNyliumPattern(); + //FAWE end /** * Create a new flora generator. @@ -101,17 +109,75 @@ public class FloraGenerator implements RegionFunction { return pattern; } + //FAWE start + /** + * Get a pattern for plants to place inside a mushroom environment. + * + * @return a pattern that places flora + */ + public static Pattern mushroomPattern() { + RandomPattern pattern = new RandomPattern(); + pattern.add(BlockTypes.RED_MUSHROOM.getDefaultState(), 10); + pattern.add(BlockTypes.BROWN_MUSHROOM.getDefaultState(), 10); + return pattern; + } + + /** + * Get a pattern for plants to place inside a nether environment. + * + * @return a pattern that places flora + */ + public static Pattern netherPattern() { + RandomPattern pattern = new RandomPattern(); + pattern.add(BlockTypes.CRIMSON_ROOTS.getDefaultState(), 10); + pattern.add(BlockTypes.CRIMSON_FUNGUS.getDefaultState(), 20); + pattern.add(BlockTypes.WARPED_FUNGUS.getDefaultState(), 5); + return pattern; + } + + /** + * Get a pattern for plants to place inside a nether environment. + * + * @return a pattern that places flora + */ + public static Pattern warpedNyliumPattern() { + RandomPattern pattern = new RandomPattern(); + pattern.add(BlockTypes.WARPED_ROOTS.getDefaultState(), 15); + pattern.add(BlockTypes.NETHER_SPROUTS.getDefaultState(), 20); + pattern.add(BlockTypes.WARPED_FUNGUS.getDefaultState(), 7); + pattern.add(BlockTypes.CRIMSON_ROOTS.getDefaultState(), 10); + return pattern; + } + //FAWE end + @Override public boolean apply(BlockVector3 position) throws WorldEditException { + //FAWE start + int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion(); + //FAWE end BlockState block = editSession.getBlock(position); if (block.getBlockType() == BlockTypes.GRASS_BLOCK) { editSession.setBlock(position.add(0, 1, 0), temperatePattern.applyBlock(position)); return true; - } else if (block.getBlockType() == BlockTypes.SAND) { + //FAWE start - add red sand + } else if (block.getBlockType() == BlockTypes.SAND || block.getBlockType() == BlockTypes.RED_SAND) { + //FAWE end editSession.setBlock(position.add(0, 1, 0), desertPattern.applyBlock(position)); return true; + //FAWE start - add new types + } else if (block.getBlockType() == BlockTypes.MYCELIUM || block.getBlockType() == BlockTypes.NETHERRACK) { + editSession.setBlock(position.add(0, 1, 0), mushroomPattern.applyBlock(position)); + return true; + } else if (dataVersion >= Constants.DATA_VERSION_MC_1_16) { + if (block.getBlockType() == BlockTypes.SOUL_SOIL || block.getBlockType() == BlockTypes.CRIMSON_NYLIUM) { + editSession.setBlock(position.add(0, 1, 0), netherPattern.applyBlock(position)); + return true; + } else if (block.getBlockType() == BlockTypes.WARPED_NYLIUM) { + editSession.setBlock(position.add(0, 1, 0), warpedNyliumPattern.applyBlock(position)); + } } + //FAWE end return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index c7dd577c1..7e5a4abf1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -210,9 +210,9 @@ public class BlockMask extends ABlockMask { @Override public boolean replacesAir() { - return ordinals[BlockTypes.AIR.getDefaultState().getOrdinal()] - || ordinals[BlockTypes.CAVE_AIR.getDefaultState().getOrdinal()] - || ordinals[BlockTypes.VOID_AIR.getDefaultState().getOrdinal()]; + return ordinals[1] + || ordinals[2] + || ordinals[3]; } @Override @@ -334,9 +334,9 @@ public class BlockMask extends ABlockMask { cloned[i] = !cloned[i]; } if (replacesAir()) { - cloned[BlockTypes.AIR.getDefaultState().getOrdinal()] = false; - cloned[BlockTypes.CAVE_AIR.getDefaultState().getOrdinal()] = false; - cloned[BlockTypes.VOID_AIR.getDefaultState().getOrdinal()] = false; + cloned[1] = false; + cloned[2] = false; + cloned[3] = false; cloned[0] = false; } return new BlockMask(getExtent(), cloned); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java index 91e92964f..2c809ada4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/OffsetMask.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.function.mask; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector3; import javax.annotation.Nullable; @@ -47,7 +49,10 @@ public class OffsetMask extends AbstractMask { */ @Deprecated public OffsetMask(Mask mask, BlockVector3 offset) { - this(mask, offset, 0, 255); + this(mask, offset, + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY() + ); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index 7966f1217..c1b36ef6b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -28,7 +28,9 @@ import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; @@ -110,7 +112,10 @@ public abstract class BreadthFirstSearch implements Operation { */ public BreadthFirstSearch(RegionFunction function) { //FAWE start - int depth, min/max y - this(function, Integer.MAX_VALUE, 0, 255, null); + this(function, Integer.MAX_VALUE, + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(), null + ); } //FAWE start - int depth, min/max y, preloading @@ -290,13 +295,13 @@ public abstract class BreadthFirstSearch implements Operation { BlockVectorSet chunkLoadSet = new BlockVectorSet(); for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) { int loadCount = 0; - if (singleQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) { + if (singleQueue != null && Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT > 1) { int cx = Integer.MIN_VALUE; int cz = Integer.MIN_VALUE; outer: for (BlockVector3 from : queue) { for (BlockVector3 direction : dirs) { - if (loadCount > Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT) { + if (loadCount > Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT) { break outer; } int x = from.getBlockX() + direction.getBlockX(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java index 7ea7f99e6..f8204b085 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.function.visitor; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; @@ -48,7 +50,10 @@ public class DownwardVisitor extends RecursiveVisitor { @Deprecated public DownwardVisitor(Mask mask, RegionFunction function, int baseY) { //FAWE start - int depth, min/max y - this(mask, function, baseY, Integer.MAX_VALUE, 0, 255, null); + this(mask, function, baseY, Integer.MAX_VALUE, WorldEdit + .getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(), null + ); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java index c4dedc1b3..90e8f01d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.function.visitor; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; @@ -39,7 +41,10 @@ public class NonRisingVisitor extends RecursiveVisitor { @Deprecated public NonRisingVisitor(Mask mask, RegionFunction function) { //FAWE start - int depth, y min/max - this(mask, function, Integer.MAX_VALUE, 0, 255, null); + this(mask, function, Integer.MAX_VALUE, WorldEdit + .getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(), null + ); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java index 861210a46..dd18f9d1f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.function.visitor; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; @@ -41,7 +43,10 @@ public class RecursiveVisitor extends BreadthFirstSearch { * @param function the function */ public RecursiveVisitor(Mask mask, RegionFunction function) { - this(mask, function, Integer.MAX_VALUE, 0, 255, null); + this(mask, function, Integer.MAX_VALUE, WorldEdit + .getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(), + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(), null + ); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index c12c793ef..ff6b67e03 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -93,7 +93,7 @@ public class RegionVisitor implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { //FAWE start > allow chunk preloading - if (singleQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) { + if (singleQueue != null && Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT > 1) { /* * The following is done to reduce iteration cost * - Preload chunks just in time @@ -107,7 +107,7 @@ public class RegionVisitor implements Operation { int lastTrailChunkZ = Integer.MIN_VALUE; int lastLeadChunkX = Integer.MIN_VALUE; int lastLeadChunkZ = Integer.MIN_VALUE; - int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT; + int loadingTarget = Settings.settings().QUEUE.PRELOAD_CHUNK_COUNT; while (trailIter.hasNext()) { BlockVector3 pt = trailIter.next(); apply(pt); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java index 713458e65..2068b9947 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/Constants.java @@ -44,19 +44,18 @@ public final class Constants { /** * The DataVersion for Minecraft 1.13 + * @deprecated If Fawe drops interaction with 1.13, this method is subject to removal. */ + @Deprecated(forRemoval = true, since = "2.0.0") public static final int DATA_VERSION_MC_1_13 = 1519; /** * The DataVersion for Minecraft 1.13.2 + * @deprecated If Fawe drops interaction with 1.13, this method is subject to removal. */ + @Deprecated(forRemoval = true, since = "2.0.0") public static final int DATA_VERSION_MC_1_13_2 = 1631; - /** - * The DataVersion for Minecraft 1.14 - */ - public static final int DATA_VERSION_MC_1_14 = 1952; - /** * The DataVersion for Minecraft 1.15 */ @@ -72,4 +71,9 @@ public final class Constants { */ public static final int DATA_VERSION_MC_1_17 = 2724; + /** + * The DataVersion for Minecraft 1.18 + */ + public static final int DATA_VERSION_MC_1_18 = 2860; + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java index 2eeab1287..75907138d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/SchematicsEventListener.java @@ -39,7 +39,7 @@ public class SchematicsEventListener { try { Files.createDirectories(config.resolve(event.getConfiguration().saveDir)); } catch (FileAlreadyExistsException e) { - LOGGER.info("Schematic directory exists as file. Possible symlink.", e); + LOGGER.debug("Schematic directory exists as file. Possible symlink.", e); } catch (IOException e) { LOGGER.warn("Failed to create schematics directory", e); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ErrorReporting.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ErrorReporting.java new file mode 100644 index 000000000..fa5b95868 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ErrorReporting.java @@ -0,0 +1,43 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.util; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.google.common.base.Throwables; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; + +/** + * Simple class for handling error reporting to users. + */ +public class ErrorReporting { + private ErrorReporting() { + } + + public static void trigger(Actor actor, Throwable error) { + actor.printError(Caption.of("worldedit.command.error.report")); + actor.print( + TextComponent.builder(error.getClass().getName() + ": " + error.getMessage()) + .hoverEvent(HoverEvent.showText(TextComponent.of(Throwables.getStackTraceAsString(error)))) + .build() + ); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java index 9015a17ac..7d6d7cedd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/HeightMapFilter.java @@ -105,7 +105,7 @@ public class HeightMapFilter { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { - outData[index++] = (int) calculateHeight(inDataFloat, width, height, offset, matrix, x, y); + outData[index++] = (int) Math.floor(calculateHeight(inDataFloat, width, height, offset, matrix, x, y)); } } return outData; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java index df030639e..7de599f39 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/convolution/SnowHeightMap.java @@ -178,13 +178,13 @@ public class SnowHeightMap { ++blocksChanged; // Grow -- start from 1 below top replacing airblocks - for (int y = (int) newHeight - 1 - originY; y >= 0; --y) { - if (y >= newHeight - 1 - originY - layerBlocks) { + for (int y = (int) Math.floor(newHeight - 1 - originY); y >= 0; --y) { + if (y >= Math.floor(newHeight - 1 - originY - layerBlocks)) { //FAWE start - avoid BlockVector3 creation for no reason session.setBlock(xr, originY + y, zr, fillerSnow); //FAWE end } else { - int copyFrom = (int) (y * scale); + int copyFrom = (int) Math.floor(y * scale); //FAWE start - avoid BlockVector3 creation for no reason BlockState block = session.getBlock(xr, originY + copyFrom, zr); session.setBlock(xr, originY + y, zr, block); @@ -195,13 +195,13 @@ public class SnowHeightMap { } } else { // Shrink -- start from bottom - for (int y = 0; y < (int) newHeight - originY; ++y) { - if (y >= (int) newHeight - originY - layerBlocks) { + for (int y = 0; y < (int) Math.floor(newHeight - originY); ++y) { + if (y >= (int) Math.floor(newHeight - originY - layerBlocks)) { //FAWE start - avoid BlockVector3 creation for no reason session.setBlock(xr, originY + y, zr, fillerSnow); //FAWE end } else { - int copyFrom = (int) (y * scale); + int copyFrom = (int) Math.floor(y * scale); //FAWE start - avoid BlockVector3 creation for no reason BlockState block = session.getBlock(xr, originY + copyFrom, zr); session.setBlock(xr, originY + y, zr, block); @@ -214,7 +214,7 @@ public class SnowHeightMap { ++blocksChanged; // Fill rest with air - for (int y = (int) newHeight + 1; y <= curHeight; ++y) { + for (int y = (int) Math.floor(newHeight + 1); y <= Math.floor(curHeight); ++y) { //FAWE start - avoid BlockVector3 creation for no reason session.setBlock(xr, y, zr, fillerAir); //FAWE end @@ -229,7 +229,8 @@ public class SnowHeightMap { } private void setSnowLayer(int x, int z, float newHeight) throws MaxChangedBlocksException { - int numOfLayers = (int) ((newHeight % 1) * 8) + 1; + int y = (int) Math.floor(newHeight); + int numOfLayers = (int) ((newHeight - y) * 8) + 1; //FAWE start - avoid BlockVector3 creation for no reason session.setBlock(x, (int) newHeight, z, BlockTypes.SNOW.getDefaultState().with(LAYERS, numOfLayers)); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index 2768f914b..4728271c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -20,6 +20,8 @@ package com.sk89q.worldedit.regions; import com.fastasyncworldedit.core.math.BlockVectorSet; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -221,14 +223,22 @@ public abstract class AbstractRegion extends AbstractSet implement // Sub-class utilities protected final int getWorldMinY() { - //FAWE start > Integer.MIN_VALUE -> 0 (to avoid crazy for loops...) TODO: See if there's a way to find a "server default" - return world == null ? 0 : world.getMinY(); + //FAWE start > Server default based on version + return world == null ? WorldEdit + .getInstance() + .getPlatformManager() + .queryCapability(Capability.WORLD_EDITING) + .versionMinY() : world.getMinY(); //FAWE end } protected final int getWorldMaxY() { - //FAWE start > Integer.MAX_VALUE -> 255 (to avoid crazy for loops...) TODO: See if there's a way to find a "server default" - return world == null ? 255 : world.getMaxY(); + //FAWE start > Server default based on version + return world == null ? WorldEdit + .getInstance() + .getPlatformManager() + .queryCapability(Capability.WORLD_EDITING) + .versionMaxY() : world.getMaxY(); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 4cf937ac4..82e89aee7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -467,7 +467,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @Override public Iterator iterator() { //FAWE start - if (Settings.IMP.HISTORY.COMPRESSION_LEVEL >= 9) { + if (Settings.settings().HISTORY.COMPRESSION_LEVEL >= 9) { return iterator_old(); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 22f1f34e5..407530eea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -29,6 +29,8 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; @@ -226,7 +228,18 @@ public interface Region extends Iterable, Cloneable, IBatchProcess BlockVector3 pos1 = getMinimumPoint(); BlockVector3 pos2 = getMaximumPoint(); return pos1.getBlockX() == Integer.MIN_VALUE && pos1.getBlockZ() == Integer.MIN_VALUE && pos2.getBlockX() == Integer.MAX_VALUE && pos2 - .getBlockZ() == Integer.MAX_VALUE && pos1.getBlockY() <= 0 && pos2.getBlockY() >= 255; + .getBlockZ() == Integer.MAX_VALUE + && pos1.getBlockY() <= WorldEdit + .getInstance() + .getPlatformManager() + .queryCapability( + Capability.WORLD_EDITING) + .versionMinY() + && pos2.getBlockY() >= WorldEdit + .getInstance() + .getPlatformManager() + .queryCapability(Capability.WORLD_EDITING) + .versionMaxY(); } default int getMinimumY() { @@ -430,7 +443,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int by = layer << 4; int ty = by + 15; if (containsEntireCuboid(bx, tx, by, ty, bz, tz)) { - set.setBlocks(layer, FaweCache.IMP.EMPTY_CHAR_4096); + set.setBlocks(layer, FaweCache.INSTANCE.EMPTY_CHAR_4096); processExtra = true; continue; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index f4b51a8d4..a58524825 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -61,17 +61,6 @@ public class RegionIntersection extends AbstractRegion { this(null, regions); } - /** - * Create a new instance with the included list of regions. - * - * @param regions a list of regions, which is copied - * @deprecated Use {@link #RegionIntersection(List)} to match upstream - */ - @Deprecated(forRemoval = true) - public RegionIntersection(Collection regions) { - this(null, regions); - } - /** * Create a new instance with the included list of regions. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 1f498a873..53b47bbae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -20,9 +20,11 @@ package com.sk89q.worldedit.world; import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; @@ -66,12 +68,12 @@ public abstract class AbstractWorld implements World { @Override public int getMinY() { - return 0; + return WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMinY(); } @Override public int getMaxY() { - return 255; + return WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).versionMaxY(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index 14fb05834..9df060bf6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -121,12 +121,12 @@ public final class BlockTypes { @Nullable public static final BlockType BEDROCK = init(); @Nullable - public static final BlockType BEE_NEST = init(); - @Nullable public static final BlockType BEEHIVE = init(); @Nullable public static final BlockType BEETROOTS = init(); @Nullable + public static final BlockType BEE_NEST = init(); + @Nullable public static final BlockType BELL = init(); @Nullable public static final BlockType BIG_DRIPLEAF = init(); @@ -163,6 +163,14 @@ public final class BlockTypes { @Nullable public static final BlockType BIRCH_WOOD = init(); @Nullable + public static final BlockType BLACKSTONE = init(); + @Nullable + public static final BlockType BLACKSTONE_SLAB = init(); + @Nullable + public static final BlockType BLACKSTONE_STAIRS = init(); + @Nullable + public static final BlockType BLACKSTONE_WALL = init(); + @Nullable public static final BlockType BLACK_BANNER = init(); @Nullable public static final BlockType BLACK_BED = init(); @@ -191,14 +199,6 @@ public final class BlockTypes { @Nullable public static final BlockType BLACK_WOOL = init(); @Nullable - public static final BlockType BLACKSTONE = init(); - @Nullable - public static final BlockType BLACKSTONE_SLAB = init(); - @Nullable - public static final BlockType BLACKSTONE_STAIRS = init(); - @Nullable - public static final BlockType BLACKSTONE_WALL = init(); - @Nullable public static final BlockType BLAST_FURNACE = init(); @Nullable public static final BlockType BLUE_BANNER = init(); @@ -247,14 +247,14 @@ public final class BlockTypes { @Nullable public static final BlockType BREWING_STAND = init(); @Nullable + public static final BlockType BRICKS = init(); + @Nullable public static final BlockType BRICK_SLAB = init(); @Nullable public static final BlockType BRICK_STAIRS = init(); @Nullable public static final BlockType BRICK_WALL = init(); @Nullable - public static final BlockType BRICKS = init(); - @Nullable public static final BlockType BROWN_BANNER = init(); @Nullable public static final BlockType BROWN_BED = init(); @@ -389,8 +389,6 @@ public final class BlockTypes { @Nullable public static final BlockType COPPER_BLOCK = init(); @Nullable - public static final BlockType COPPER_ORE = init(); - @Nullable public static final BlockType CORNFLOWER = init(); @Nullable public static final BlockType CRACKED_DEEPSLATE_BRICKS = init(); @@ -571,14 +569,14 @@ public final class BlockTypes { @Nullable public static final BlockType DEEPSLATE = init(); @Nullable + public static final BlockType DEEPSLATE_BRICKS = init(); + @Nullable public static final BlockType DEEPSLATE_BRICK_SLAB = init(); @Nullable public static final BlockType DEEPSLATE_BRICK_STAIRS = init(); @Nullable public static final BlockType DEEPSLATE_BRICK_WALL = init(); @Nullable - public static final BlockType DEEPSLATE_BRICKS = init(); - @Nullable public static final BlockType DEEPSLATE_COAL_ORE = init(); @Nullable public static final BlockType DEEPSLATE_COPPER_ORE = init(); @@ -595,14 +593,14 @@ public final class BlockTypes { @Nullable public static final BlockType DEEPSLATE_REDSTONE_ORE = init(); @Nullable + public static final BlockType DEEPSLATE_TILES = init(); + @Nullable public static final BlockType DEEPSLATE_TILE_SLAB = init(); @Nullable public static final BlockType DEEPSLATE_TILE_STAIRS = init(); @Nullable public static final BlockType DEEPSLATE_TILE_WALL = init(); @Nullable - public static final BlockType DEEPSLATE_TILES = init(); - @Nullable public static final BlockType DETECTOR_RAIL = init(); @Nullable public static final BlockType DIAMOND_BLOCK = init(); @@ -641,6 +639,8 @@ public final class BlockTypes { @Nullable public static final BlockType ENCHANTING_TABLE = init(); @Nullable + public static final BlockType ENDER_CHEST = init(); + @Nullable public static final BlockType END_GATEWAY = init(); @Nullable public static final BlockType END_PORTAL = init(); @@ -651,18 +651,16 @@ public final class BlockTypes { @Nullable public static final BlockType END_STONE = init(); @Nullable + public static final BlockType END_STONE_BRICKS = init(); + @Nullable public static final BlockType END_STONE_BRICK_SLAB = init(); @Nullable public static final BlockType END_STONE_BRICK_STAIRS = init(); @Nullable public static final BlockType END_STONE_BRICK_WALL = init(); @Nullable - public static final BlockType END_STONE_BRICKS = init(); - @Nullable public static final BlockType EXPOSED_COPPER = init(); @Nullable - public static final BlockType ENDER_CHEST = init(); - @Nullable public static final BlockType EXPOSED_CUT_COPPER = init(); @Nullable public static final BlockType EXPOSED_CUT_COPPER_SLAB = init(); @@ -685,12 +683,12 @@ public final class BlockTypes { @Nullable public static final BlockType FLETCHING_TABLE = init(); @Nullable - public static final BlockType FLOWER_POT = init(); - @Nullable public static final BlockType FLOWERING_AZALEA = init(); @Nullable public static final BlockType FLOWERING_AZALEA_LEAVES = init(); @Nullable + public static final BlockType FLOWER_POT = init(); + @Nullable public static final BlockType FROSTED_ICE = init(); @Nullable public static final BlockType FURNACE = init(); @@ -701,10 +699,10 @@ public final class BlockTypes { @Nullable public static final BlockType GLASS_PANE = init(); @Nullable - public static final BlockType GLOW_LICHEN = init(); - @Nullable public static final BlockType GLOWSTONE = init(); @Nullable + public static final BlockType GLOW_LICHEN = init(); + @Nullable public static final BlockType GOLD_BLOCK = init(); @Nullable public static final BlockType GOLD_ORE = init(); @@ -720,9 +718,6 @@ public final class BlockTypes { public static final BlockType GRASS = init(); @Nullable public static final BlockType GRASS_BLOCK = init(); - @Deprecated - @Nullable - public static final BlockType GRASS_PATH = init(); @Nullable public static final BlockType GRAVEL = init(); @Nullable @@ -790,10 +785,10 @@ public final class BlockTypes { @Nullable public static final BlockType HEAVY_WEIGHTED_PRESSURE_PLATE = init(); @Nullable - public static final BlockType HONEY_BLOCK = init(); - @Nullable public static final BlockType HONEYCOMB_BLOCK = init(); @Nullable + public static final BlockType HONEY_BLOCK = init(); + @Nullable public static final BlockType HOPPER = init(); @Nullable public static final BlockType HORN_CORAL = init(); @@ -892,6 +887,8 @@ public final class BlockTypes { @Nullable public static final BlockType LIGHT = init(); @Nullable + public static final BlockType LIGHTNING_ROD = init(); + @Nullable public static final BlockType LIGHT_BLUE_BANNER = init(); @Nullable public static final BlockType LIGHT_BLUE_BED = init(); @@ -950,8 +947,6 @@ public final class BlockTypes { @Nullable public static final BlockType LIGHT_WEIGHTED_PRESSURE_PLATE = init(); @Nullable - public static final BlockType LIGHTNING_ROD = init(); - @Nullable public static final BlockType LILAC = init(); @Nullable public static final BlockType LILY_OF_THE_VALLEY = init(); @@ -1026,10 +1021,6 @@ public final class BlockTypes { @Nullable public static final BlockType MELON_STEM = init(); @Nullable - public static final BlockType MOSS_BLOCK = init(); - @Nullable - public static final BlockType MOSS_CARPET = init(); - @Nullable public static final BlockType MOSSY_COBBLESTONE = init(); @Nullable public static final BlockType MOSSY_COBBLESTONE_SLAB = init(); @@ -1038,13 +1029,17 @@ public final class BlockTypes { @Nullable public static final BlockType MOSSY_COBBLESTONE_WALL = init(); @Nullable + public static final BlockType MOSSY_STONE_BRICKS = init(); + @Nullable public static final BlockType MOSSY_STONE_BRICK_SLAB = init(); @Nullable public static final BlockType MOSSY_STONE_BRICK_STAIRS = init(); @Nullable public static final BlockType MOSSY_STONE_BRICK_WALL = init(); @Nullable - public static final BlockType MOSSY_STONE_BRICKS = init(); + public static final BlockType MOSS_BLOCK = init(); + @Nullable + public static final BlockType MOSS_CARPET = init(); @Nullable public static final BlockType MOVING_PISTON = init(); @Nullable @@ -1052,6 +1047,12 @@ public final class BlockTypes { @Nullable public static final BlockType MYCELIUM = init(); @Nullable + public static final BlockType NETHERITE_BLOCK = init(); + @Nullable + public static final BlockType NETHERRACK = init(); + @Nullable + public static final BlockType NETHER_BRICKS = init(); + @Nullable public static final BlockType NETHER_BRICK_FENCE = init(); @Nullable public static final BlockType NETHER_BRICK_SLAB = init(); @@ -1060,8 +1061,6 @@ public final class BlockTypes { @Nullable public static final BlockType NETHER_BRICK_WALL = init(); @Nullable - public static final BlockType NETHER_BRICKS = init(); - @Nullable public static final BlockType NETHER_GOLD_ORE = init(); @Nullable public static final BlockType NETHER_PORTAL = init(); @@ -1074,10 +1073,6 @@ public final class BlockTypes { @Nullable public static final BlockType NETHER_WART_BLOCK = init(); @Nullable - public static final BlockType NETHERITE_BLOCK = init(); - @Nullable - public static final BlockType NETHERRACK = init(); - @Nullable public static final BlockType NOTE_BLOCK = init(); @Nullable public static final BlockType OAK_BUTTON = init(); @@ -1212,14 +1207,14 @@ public final class BlockTypes { @Nullable public static final BlockType POLISHED_BLACKSTONE = init(); @Nullable + public static final BlockType POLISHED_BLACKSTONE_BRICKS = init(); + @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_SLAB = init(); @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_STAIRS = init(); @Nullable public static final BlockType POLISHED_BLACKSTONE_BRICK_WALL = init(); @Nullable - public static final BlockType POLISHED_BLACKSTONE_BRICKS = init(); - @Nullable public static final BlockType POLISHED_BLACKSTONE_BUTTON = init(); @Nullable public static final BlockType POLISHED_BLACKSTONE_PRESSURE_PLATE = init(); @@ -1257,9 +1252,12 @@ public final class BlockTypes { public static final BlockType POTTED_ACACIA_SAPLING = init(); @Nullable public static final BlockType POTTED_ALLIUM = init(); + @Deprecated //No longer has "bush" @Nullable public static final BlockType POTTED_AZALEA_BUSH = init(); @Nullable + public static final BlockType POTTED_AZALEA = init(); + @Nullable public static final BlockType POTTED_AZURE_BLUET = init(); @Nullable public static final BlockType POTTED_BAMBOO = init(); @@ -1285,9 +1283,12 @@ public final class BlockTypes { public static final BlockType POTTED_DEAD_BUSH = init(); @Nullable public static final BlockType POTTED_FERN = init(); + @Deprecated //No longer has "bush" @Nullable public static final BlockType POTTED_FLOWERING_AZALEA_BUSH = init(); @Nullable + public static final BlockType POTTED_FLOWERING_AZALEA = init(); + @Nullable public static final BlockType POTTED_JUNGLE_SAPLING = init(); @Nullable public static final BlockType POTTED_LILY_OF_THE_VALLEY = init(); @@ -1324,12 +1325,12 @@ public final class BlockTypes { @Nullable public static final BlockType PRISMARINE = init(); @Nullable + public static final BlockType PRISMARINE_BRICKS = init(); + @Nullable public static final BlockType PRISMARINE_BRICK_SLAB = init(); @Nullable public static final BlockType PRISMARINE_BRICK_STAIRS = init(); @Nullable - public static final BlockType PRISMARINE_BRICKS = init(); - @Nullable public static final BlockType PRISMARINE_SLAB = init(); @Nullable public static final BlockType PRISMARINE_STAIRS = init(); @@ -1394,6 +1395,18 @@ public final class BlockTypes { @Nullable public static final BlockType RAW_IRON_BLOCK = init(); @Nullable + public static final BlockType REDSTONE_BLOCK = init(); + @Nullable + public static final BlockType REDSTONE_LAMP = init(); + @Nullable + public static final BlockType REDSTONE_ORE = init(); + @Nullable + public static final BlockType REDSTONE_TORCH = init(); + @Nullable + public static final BlockType REDSTONE_WALL_TORCH = init(); + @Nullable + public static final BlockType REDSTONE_WIRE = init(); + @Nullable public static final BlockType RED_BANNER = init(); @Nullable public static final BlockType RED_BED = init(); @@ -1414,14 +1427,14 @@ public final class BlockTypes { @Nullable public static final BlockType RED_MUSHROOM_BLOCK = init(); @Nullable + public static final BlockType RED_NETHER_BRICKS = init(); + @Nullable public static final BlockType RED_NETHER_BRICK_SLAB = init(); @Nullable public static final BlockType RED_NETHER_BRICK_STAIRS = init(); @Nullable public static final BlockType RED_NETHER_BRICK_WALL = init(); @Nullable - public static final BlockType RED_NETHER_BRICKS = init(); - @Nullable public static final BlockType RED_SAND = init(); @Nullable public static final BlockType RED_SANDSTONE = init(); @@ -1446,18 +1459,6 @@ public final class BlockTypes { @Nullable public static final BlockType RED_WOOL = init(); @Nullable - public static final BlockType REDSTONE_BLOCK = init(); - @Nullable - public static final BlockType REDSTONE_LAMP = init(); - @Nullable - public static final BlockType REDSTONE_ORE = init(); - @Nullable - public static final BlockType REDSTONE_TORCH = init(); - @Nullable - public static final BlockType REDSTONE_WALL_TORCH = init(); - @Nullable - public static final BlockType REDSTONE_WIRE = init(); - @Nullable public static final BlockType REPEATER = init(); @Nullable public static final BlockType REPEATING_COMMAND_BLOCK = init(); @@ -1482,12 +1483,12 @@ public final class BlockTypes { @Nullable public static final BlockType SCULK_SENSOR = init(); @Nullable + public static final BlockType SEAGRASS = init(); + @Nullable public static final BlockType SEA_LANTERN = init(); @Nullable public static final BlockType SEA_PICKLE = init(); @Nullable - public static final BlockType SEAGRASS = init(); - @Nullable public static final BlockType SHROOMLIGHT = init(); @Nullable public static final BlockType SHULKER_BOX = init(); @@ -1591,14 +1592,16 @@ public final class BlockTypes { @Nullable public static final BlockType STONE = init(); @Nullable + public static final BlockType STONECUTTER = init(); + @Nullable + public static final BlockType STONE_BRICKS = init(); + @Nullable public static final BlockType STONE_BRICK_SLAB = init(); @Nullable public static final BlockType STONE_BRICK_STAIRS = init(); @Nullable public static final BlockType STONE_BRICK_WALL = init(); @Nullable - public static final BlockType STONE_BRICKS = init(); - @Nullable public static final BlockType STONE_BUTTON = init(); @Nullable public static final BlockType STONE_PRESSURE_PLATE = init(); @@ -1607,8 +1610,6 @@ public final class BlockTypes { @Nullable public static final BlockType STONE_STAIRS = init(); @Nullable - public static final BlockType STONECUTTER = init(); - @Nullable public static final BlockType STRIPPED_ACACIA_LOG = init(); @Nullable public static final BlockType STRIPPED_ACACIA_WOOD = init(); @@ -1772,10 +1773,10 @@ public final class BlockTypes { @Nullable public static final BlockType WEATHERED_CUT_COPPER_SLAB = init(); @Nullable - public static final BlockType WEEPING_VINES = init(); - @Nullable public static final BlockType WEATHERED_CUT_COPPER_STAIRS = init(); @Nullable + public static final BlockType WEEPING_VINES = init(); + @Nullable public static final BlockType WEEPING_VINES_PLANT = init(); @Nullable public static final BlockType WET_SPONGE = init(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java index d476c092c..325da5140 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java @@ -2,7 +2,6 @@ package com.sk89q.worldedit.world.block; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.world.block.BlockID; import com.google.common.primitives.Booleans; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; @@ -218,37 +217,41 @@ public class BlockTypesCache { : item, item -> item)); int size = blockMap.size() + 1; - Field[] idFields = BlockID.class.getDeclaredFields(); - for (Field field : idFields) { - size = Math.max(field.getInt(null) + 1, size); - } BIT_OFFSET = MathMan.log2nlz(size); BIT_MASK = ((1 << BIT_OFFSET) - 1); values = new BlockType[size]; - // Register the statically declared ones first - for (Field field : idFields) { - if (field.getType() == int.class) { - int internalId = field.getInt(null); - String id = "minecraft:" + field.getName().toLowerCase(Locale.ROOT); - String defaultState = blockMap.remove(id); - if (defaultState == null) { - if (internalId != 0) { - continue; + // Register reserved IDs. Ensure air/reserved are 0/1/2/3 + { + for (Field field : ReservedIDs.class.getDeclaredFields()) { + if (field.getType() == int.class) { + int internalId = field.getInt(null); + String id = "minecraft:" + field.getName().toLowerCase(Locale.ROOT); + String defaultState = blockMap.remove(id); + if (defaultState == null) { + defaultState = id; } - defaultState = id; + if (values[internalId] != null) { + // Ugly way of ensuring a stacktrace is printed so we can see the culprit. Rethrow because we still + // want to cancel whatever initialised the class. + try { + throw new IllegalStateException(String.format( + "Invalid duplicate id for %s! Something has gone very wrong. Are " + + "any plugins shading FAWE?!", id)); + } catch (IllegalStateException e) { + e.printStackTrace(); + throw e; + } + } + BlockType type = register(defaultState, internalId, stateList, tickList); + // Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty + values[internalId] = type; } - if (values[internalId] != null) { - throw new IllegalStateException("Invalid duplicate id for " + field.getName()); - } - BlockType type = register(defaultState, internalId, stateList, tickList); - // Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty - values[internalId] = type; } } - { // Register new blocks - int internalId = 1; + { // Register real blocks + int internalId = 0; for (Map.Entry entry : blockMap.entrySet()) { String defaultState = entry.getValue(); // Skip already registered ids @@ -308,4 +311,15 @@ public class BlockTypesCache { } } + /** + * Statically-set reserved IDs. Should be used as minimally as possible, and for IDs that will see frequent use + */ + public static class ReservedIDs { + public static final int __RESERVED__ = 0; + public static final int AIR = 1; + public static final int CAVE_AIR = 2; + public static final int VOID_AIR = 3; + + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java new file mode 100644 index 000000000..b8e54bc04 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/package-info.java @@ -0,0 +1,6 @@ +/** + * The following classes are FAWE additions: + * + * @see com.sk89q.worldedit.world.block.BlockTypesCache + */ +package com.sk89q.worldedit.world.block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java index 1e507e58c..92f7f6caf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.storage.InvalidFormatException; /** - * The chunk format for Minecraft 1.16 and newer + * The chunk format for Minecraft 1.16 and 1.17 */ public class AnvilChunk16 extends AnvilChunk15 { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java new file mode 100644 index 000000000..6d8348d5e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -0,0 +1,218 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.chunk; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.storage.InvalidFormatException; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The chunk format for Minecraft 1.18 and newer + */ +public class AnvilChunk18 implements Chunk { + + private final CompoundTag rootTag; + private final Int2ObjectOpenHashMap blocks; + private final int rootX; + private final int rootZ; + + private Map> tileEntities; + + /** + * Construct the chunk with a compound tag. + * + * @param tag the tag to read + * @throws DataException on a data error + */ + public AnvilChunk18(CompoundTag tag) throws DataException { + rootTag = tag; + + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + + List sections = NBTUtils.getChildTag(rootTag.getValue(), "sections", ListTag.class).getValue(); + blocks = new Int2ObjectOpenHashMap<>(sections.size()); + + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag sectionTag)) { + continue; + } + + Object yValue = sectionTag.getValue().get("Y").getValue(); // sometimes a byte, sometimes an int + if (!(yValue instanceof Number)) { + throw new InvalidFormatException("Y is not numeric: " + yValue); + } + int y = ((Number) yValue).intValue(); + + Tag rawBlockStatesTag = sectionTag.getValue().get("block_states"); // null for sections outside of the world limits + if (rawBlockStatesTag instanceof CompoundTag blockStatesTag) { + + // parse palette + List paletteEntries = blockStatesTag.getList("palette", CompoundTag.class); + int paletteSize = paletteEntries.size(); + if (paletteSize == 0) { + continue; + } + BlockState[] palette = new BlockState[paletteSize]; + for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { + CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); + BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + if (type == null) { + throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + } + BlockState blockState = type.getDefaultState(); + if (paletteEntry.containsKey("Properties")) { + CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class); + for (Property property : blockState.getStates().keySet()) { + if (properties.containsKey(property.getName())) { + String value = properties.getString(property.getName()); + try { + blockState = getBlockStateWith(blockState, property, value); + } catch (IllegalArgumentException e) { + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); + } + } + } + } + palette[paletteEntryId] = blockState; + } + if (paletteSize == 1) { + // the same block everywhere + blocks.put(y, palette); + continue; + } + + // parse block states + long[] blockStatesSerialized = NBTUtils.getChildTag(blockStatesTag.getValue(), "data", LongArrayTag.class).getValue(); + + BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; + blocks.put(y, chunkSectionBlocks); + + readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); + } + } + } + + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { + PackedIntArrayReader reader = new PackedIntArrayReader(blockStatesSerialized); + for (int blockPos = 0; blockPos < chunkSectionBlocks.length; blockPos++) { + int index = reader.get(blockPos); + if (index >= palette.length) { + throw new InvalidFormatException("Invalid block state table entry: " + index); + } + chunkSectionBlocks[blockPos] = palette[index]; + } + } + + private BlockState getBlockStateWith(BlockState source, Property property, String value) { + return source.with(property, property.getValueFor(value)); + } + + /** + * Used to load the tile entities. + */ + private void populateTileEntities() throws DataException { + tileEntities = new HashMap<>(); + if (!rootTag.getValue().containsKey("block_entities")) { + return; + } + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "block_entities", ListTag.class).getValue(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag t)) { + throw new InvalidFormatException("CompoundTag expected in block_entities"); + } + + Map values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); + + BlockVector3 vec = BlockVector3.at(x, y, z); + tileEntities.put(vec, values); + } + } + + /** + * Get the map of tags keyed to strings for a block's tile entity data. May + * return null if there is no tile entity data. Not public yet because + * what this function returns isn't ideal for usage. + * + * @param position the position + * @return the compound tag for that position, which may be null + * @throws DataException thrown if there is a data error + */ + @Nullable + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { + if (tileEntities == null) { + populateTileEntities(); + } + + Map values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); + } + + @Override + public BaseBlock getBlock(BlockVector3 position) throws DataException { + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; + + int section = y >> 4; + int yIndex = y & 0x0F; + + BlockState[] sectionBlocks = blocks.get(section); + if (sectionBlocks == null) { + return BlockTypes.AIR.getDefaultState().toBaseBlock(); + } + BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)]; + + CompoundTag tileEntity = getBlockTileEntity(position); + + if (tileEntity != null) { + return state.toBaseBlock(tileEntity); + } + + return state.toBaseBlock(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java index 00970efd3..e6db601c3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.world.chunk.AnvilChunk13; import com.sk89q.worldedit.world.chunk.AnvilChunk15; import com.sk89q.worldedit.world.chunk.AnvilChunk16; import com.sk89q.worldedit.world.chunk.AnvilChunk17; +import com.sk89q.worldedit.world.chunk.AnvilChunk18; import com.sk89q.worldedit.world.chunk.Chunk; import com.sk89q.worldedit.world.chunk.OldChunk; @@ -72,8 +73,28 @@ public class ChunkStoreHelper { * @throws DataException if the rootTag is not valid chunk data */ public static Chunk getChunk(CompoundTag rootTag) throws DataException { + int dataVersion = rootTag.getInt("DataVersion"); + if (dataVersion == 0) { + dataVersion = -1; + } + + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + final int currentDataVersion = platform.getDataVersion(); + if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks + final DataFixer dataFixer = platform.getDataFixer(); + if (dataFixer != null) { + rootTag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer.fixUp(DataFixer.FixTypes.CHUNK, + rootTag.asBinaryTag(), dataVersion)); + dataVersion = currentDataVersion; + } + } + + if (dataVersion >= Constants.DATA_VERSION_MC_1_18) { + return new AnvilChunk18(rootTag); + } //FAWE start - biome and entity restore return getChunk(rootTag, () -> null); + //FAWE end } /** @@ -113,21 +134,6 @@ public class ChunkStoreHelper { if (dataVersion == 0) { dataVersion = -1; } - final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); - final int currentDataVersion = platform.getDataVersion(); - if (tag - .getValue() - .containsKey("Sections") && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks - final DataFixer dataFixer = platform.getDataFixer(); - if (dataFixer != null) { - //FAWE start - BinaryTag - tag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer - .fixUp(DataFixer.FixTypes.CHUNK, rootTag.asBinaryTag(), dataVersion) - .get("Level")); - //FAWE end - dataVersion = currentDataVersion; - } - } //FAWE start - biome and entity restore if (dataVersion >= Constants.DATA_VERSION_MC_1_17) { return new AnvilChunk17(tag, entitiesTag); @@ -153,6 +159,15 @@ public class ChunkStoreHelper { return new OldChunk(tag); } + private static boolean hasLevelSections(CompoundTag rootTag) { + Map children = rootTag.getValue(); + Tag levelTag = children.get("Level"); + if (levelTag instanceof CompoundTag) { + return ((CompoundTag) levelTag).getValue().containsKey("Sections"); + } + return false; + } + private ChunkStoreHelper() { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java index fee7a3d9e..193f03b06 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java @@ -126,7 +126,7 @@ public class McRegionReader { // The chunk hasn't been generated if (offset == 0) { - throw new DataException("The chunk at " + x + "," + z + " is not generated"); + throw new DataException("The chunk at " + position + " is not generated"); } int sectorNumber = offset >> 8; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java index f60df4510..76f9a5ba3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -105,7 +105,7 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { endIndex = entryName.lastIndexOf('\\'); } folder = entryName.substring(0, endIndex); - if (folder.endsWith("poi")) { + if (folder.endsWith("poi") || folder.endsWith("entities")) { continue; } name = folder + "/" + name; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java index a19aed26d..067515e13 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java @@ -101,9 +101,7 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { endIndex = entryName.lastIndexOf('\\'); } folder = entryName.substring(0, endIndex); - //FAWE start - biome and entity restore if (folder.endsWith("poi") || folder.endsWith("entities")) { - //FAWE end continue; } name = folder + "/" + name; diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 54c0a9c44..6f4c5a737 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -13,7 +13,7 @@ "fawe.info.worldedit.restricted": "Your FAWE edits are now restricted.", "fawe.info.worldedit.oom.admin": "Possible options:\n - //fast\n - Do smaller edits\n - Allocate more memory\n - Disable `max-memory-percent`", "fawe.info.temporarily-not-working": "Temporarily not working", - "fawe.info.update-available": "An update for FastAsyncWorldEdit is available. You are {0} build(s) out of date.\nYou are running version {1}, the latest version is {2}.\nUpdate at {3}", + "fawe.info.update-available": "An update for FastAsyncWorldEdit is available. You are {0} build(s) out of date.\nYou are running build {1}, the latest version is build {2}.\nUpdate at {3}", "fawe.web.generating.link": "Uploading {0}, please wait...", "fawe.web.generating.link.failed": "Failed to generate download link!", "fawe.web.download.link": "{0}", @@ -238,8 +238,8 @@ "worldedit.error.unknown-block": "Block name '{0}' was not recognized.", "worldedit.error.disallowed-block": "Block '{0}' not allowed (see WorldEdit configuration).", "worldedit.error.max-changes": "Max blocks changed in an operation reached ({0}).", - "worldedit.error.max-brush-radius": "Maximum brush radius (in config-legacy.yml): {0}", - "worldedit.error.max-radius": "Maximum radius (in config-legacy.yml): {0}", + "worldedit.error.max-brush-radius": "Maximum brush radius (in worldedit-config.yml): {0}", + "worldedit.error.max-radius": "Maximum radius (in worldedit-config.yml): {0}", "worldedit.error.unknown-direction": "Unknown direction: {0}", "worldedit.error.empty-clipboard": "Your clipboard is empty. Use //copy first.", "worldedit.error.invalid-filename": "Filename '{0}' invalid: {1}", diff --git a/worldedit-core/src/test/java/com/fastasyncworldedit/util/StubPlatform.java b/worldedit-core/src/test/java/com/fastasyncworldedit/util/StubPlatform.java new file mode 100644 index 000000000..6e9f81de8 --- /dev/null +++ b/worldedit-core/src/test/java/com/fastasyncworldedit/util/StubPlatform.java @@ -0,0 +1,113 @@ +package com.fastasyncworldedit.util; + +import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.AbstractPlatform; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.Registries; +import org.enginehub.piston.CommandManager; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; + +public class StubPlatform extends AbstractPlatform { + + @Override + public Registries getRegistries() { + return null; + } + + @Override + public int getDataVersion() { + return Constants.DATA_VERSION_MC_1_18; + } + + @Override + public boolean isValidMobType(final String type) { + return false; + } + + @Override + public void reload() { + + } + + @Nullable + @Override + public Player matchPlayer(final Player player) { + return null; + } + + @Nullable + @Override + public World matchWorld(final World world) { + return null; + } + + @Override + public void registerCommands(final CommandManager commandManager) { + + } + + @Override + public void setGameHooksEnabled(final boolean enabled) { + + } + + @Override + public LocalConfiguration getConfiguration() { + return null; + } + + @Override + public String getVersion() { + return "TEST"; + } + + @Override + public String getPlatformName() { + return "TEST"; + } + + @Override + public String getPlatformVersion() { + return "TEST"; + } + + @Override + public Map getCapabilities() { + Map capabilities = new EnumMap<>(Capability.class); + capabilities.put(Capability.WORLD_EDITING, Preference.PREFER_OTHERS); + return capabilities; + } + + @Override + public Set getSupportedSideEffects() { + return null; + } + + @Override + public RelighterFactory getRelighterFactory() { + return null; + } + + // Use most "extreme" value + @Override + public int versionMinY() { + return -64; + } + + // Use most "extreme" value + @Override + public int versionMaxY() { + return 319; + } + +} diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java index bb4a26739..a1582bf04 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/util/RegionOptimizedVectorSorterTest.java @@ -19,7 +19,9 @@ package com.sk89q.worldedit.internal.util; +import com.fastasyncworldedit.util.StubPlatform; import com.google.common.collect.Lists; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; @@ -71,6 +73,10 @@ public class RegionOptimizedVectorSorterTest { 0, 1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000 }) void checkSorted(int size) { + //FAWE start - required for AbstractRegion recalculation testing height limits with null world + WorldEdit.getInstance().getPlatformManager().register(new StubPlatform()); + WorldEdit.getInstance().getPlatformManager().handlePlatformsRegistered(null); + //FAWE end Random rng = new Random(size); List toSort; if (size == 0) { diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts index 73022bc99..c5eb10887 100644 --- a/worldedit-libs/core/build.gradle.kts +++ b/worldedit-libs/core/build.gradle.kts @@ -8,7 +8,6 @@ dependencies { "shade"(libs.jchronic) { exclude(group = "junit", module = "junit") } - "shade"(libs.paranamer) "shade"(libs.jlibnoise) "shade"(libs.piston) "shade"(libs.pistonRuntime)