diff --git a/.editorconfig b/.editorconfig index e43c0e094..c60879fb3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -342,7 +342,7 @@ ij_editorconfig_space_before_colon = false ij_editorconfig_space_before_comma = false ij_editorconfig_spaces_around_assignment_operators = true -[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.pom, *.rng, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}] +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] ij_xml_align_attributes = true ij_xml_align_text = false ij_xml_attribute_wrap = normal @@ -360,7 +360,7 @@ ij_xml_space_around_equals_in_attribute = false ij_xml_space_inside_empty_tag = false ij_xml_text_wrap = normal -[{*.ats, *.ts}] +[{*.ats,*.ts}] ij_continuation_indent_size = 4 ij_typescript_align_imports = false ij_typescript_align_multiline_array_initializer_expression = false @@ -528,7 +528,7 @@ ij_typescript_while_brace_force = never ij_typescript_while_on_new_line = false ij_typescript_wrap_comments = false -[{*.bash, *.sh, *.zsh}] +[{*.bash,*.sh,*.zsh}] indent_size = 2 tab_width = 2 ij_shell_binary_ops_start_line = false @@ -537,7 +537,7 @@ ij_shell_minify_program = false ij_shell_redirect_followed_by_space = false ij_shell_switch_cases_indented = false -[{*.cjs, *.js}] +[{*.cjs,*.js}] ij_continuation_indent_size = 4 ij_javascript_align_imports = false ij_javascript_align_multiline_array_initializer_expression = false @@ -702,10 +702,10 @@ ij_javascript_while_brace_force = never ij_javascript_while_on_new_line = false ij_javascript_wrap_comments = false -[{*.ft, *.vm, *.vsl}] +[{*.ft,*.vm,*.vsl}] ij_vtl_keep_indents_on_empty_lines = false -[{*.gant, *.gradle, *.groovy, *.gy}] +[{*.gant,*.gradle,*.groovy,*.gy}] ij_groovy_align_group_field_declarations = false ij_groovy_align_multiline_array_initializer_expression = false ij_groovy_align_multiline_assignment = false @@ -884,7 +884,7 @@ ij_groovy_while_brace_force = never ij_groovy_while_on_new_line = false ij_groovy_wrap_long_lines = false -[{*.gradle.kts, *.kt, *.kts, *.main.kts}] +[{*.gradle.kts,*.kt,*.kts,*.main.kts}] ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false @@ -963,7 +963,7 @@ ij_kotlin_wrap_elvis_expressions = 1 ij_kotlin_wrap_expression_body_functions = 0 ij_kotlin_wrap_first_method_in_call_chain = false -[{*.har, *.jsb2, *.jsb3, *.json, .babelrc, .eslintrc, .stylelintrc, bowerrc, jest.config, mcmod.info}] +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config,mcmod.info}] indent_size = 2 ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false @@ -976,7 +976,7 @@ ij_json_spaces_within_braces = false ij_json_spaces_within_brackets = false ij_json_wrap_long_lines = false -[{*.htm, *.html, *.sht, *.shtm, *.shtml}] +[{*.htm,*.html,*.sht,*.shtm,*.shtml}] ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 ij_html_align_attributes = true ij_html_align_text = false @@ -1004,7 +1004,7 @@ ij_html_space_inside_empty_tag = false ij_html_text_wrap = normal ij_html_uniform_ident = false -[{*.yaml, *.yml}] +[{*.yaml,*.yml}] indent_size = 2 ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 560478e0e..bc78076bd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,11 +27,10 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.2' + - '1.20.4' - '1.20' - '1.19.4' - '1.18.2' - - '1.17.1' validations: required: true diff --git a/.github/renovate.json b/.github/renovate.json index d0e59d791..3d0f91b5a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,18 +1,18 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base", + "$schema" : "https://docs.renovatebot.com/renovate-schema.json", + "extends" : [ + "config:recommended", ":semanticCommitsDisabled" ], - "automerge": true, - "ignoreDeps": [ - "guava", + "automerge" : true, + "ignoreDeps" : [ + "guava", "com.google.guava:guava", "rhino-runtime", "org.antlr", "antlr4-runtime", "fastutil", - "it.unimi.dsi:fastutil", + "it.unimi.dsi:fastutil", "auto-value-annotations", "auto-value", "com.google.code.gson:gson", @@ -29,7 +29,34 @@ "org.spongepowered:spongeapi", "org.yaml:snakeyaml" ], - "labels": ["Renovate"], - "rebaseWhen": "conflicted", - "schedule": ["on the first day of the month"] + "labels" : [ + "Renovate" + ], + "rebaseWhen" : "conflicted", + "customManagers" : [ + { + "customType" : "regex", + "datasourceTemplate" : "custom.paperweight-userdev", + "fileMatch" : "^worldedit-bukkit\\/adapters\\/adapter-\\d+_\\d+(_\\d+)?\\/build\\.gradle\\.kts$", + "matchStrings" : [ + "url=(?.*)\\s", + "paperDevBundle\\(\"(?.*?)\"\\)\\s" + ], + "matchStringsStrategy": "combination", + "depNameTemplate" : "paperweight-userdev", + "extractVersionTemplate" : "(?\\d+\\.\\d+\\.?\\d*-R0\\.1-\\d+\\.\\d+-\\d+)" + } + ], + "customDatasources" : { + "paperweight-userdev": { + "defaultRegistryUrlTemplate": "", + "format": "html" + } + }, + "packageRules" : [ + { + "matchDatasources" : ["custom.paperweight-userdev"], + "versioning": "regex:^(?\\d+)\\.(?\\d+)\\.(?\\d+)?-R0\\.1-\\d+\\d+\\.\\d+-(?\\d+)$" + } + ] } diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 98319f7d2..de239164e 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,9 +11,9 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6cda7331f..675f0cc1c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,9 +11,9 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a0cd830bd..b7e9c61ed 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,16 +21,16 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle java-version: 17 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index d189f5520..fa6f3d72d 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v2.1.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.0 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 90248b436..131fb810e 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,6 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index cb1d0a9d1..a621e9d13 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,9 +9,9 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin cache: gradle @@ -19,7 +19,7 @@ jobs: - name: Clean Build run: ./gradlew clean build --no-daemon - name: Upload Release Assets - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v3.0 with: files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar' repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/build.gradle.kts b/build.gradle.kts index 63e05aad2..15845439a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { id("io.github.gradle-nexus.publish-plugin") version "1.3.0" - id("xyz.jpenilla.run-paper") version "2.2.0" + id("xyz.jpenilla.run-paper") version "2.2.3" } if (!File("$rootDir/.git").exists()) { @@ -34,7 +34,7 @@ logger.lifecycle(""" ******************************************* """) -var rootVersion by extra("2.8.3") +var rootVersion by extra("2.9.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -83,7 +83,7 @@ allprojects { } applyCommonConfiguration() -val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.2") +val supportedVersions = listOf("1.18.2", "1.19.4", "1.20", "1.20.4") tasks { supportedVersions.forEach { @@ -97,7 +97,7 @@ tasks { } } runServer { - minecraftVersion("1.20.2") + minecraftVersion("1.20.4") pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } .toTypedArray()) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a65407ce5..e4227d576 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -22,9 +22,9 @@ val properties = Properties().also { props -> dependencies { implementation(gradleApi()) - implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") + implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2") implementation("com.github.johnrengelman:shadow:8.1.1") - implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.5") + implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") } kotlin { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 397834962..85d7a18c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Minecraft expectations -paper = "1.20.2-R0.1-SNAPSHOT" +paper = "1.20.4-R0.1-SNAPSHOT" fastutil = "8.5.9" guava = "31.1-jre" log4j = "2.19.0" @@ -11,19 +11,19 @@ snakeyaml = "2.0" dummypermscompat = "1.10" worldguard-bukkit = "7.0.9" mapmanager = "1.8.0-SNAPSHOT" -griefprevention = "16.18.1" +griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.0.1" -plotsquared = "7.1.0" +towny = "0.100.1.23" +plotsquared = "7.3.6" # Third party bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" -adventure = "4.14.0" -adventure-bukkit = "4.3.1" -checkerqual = "3.40.0" +adventure = "4.16.0" +adventure-bukkit = "4.3.2" +checkerqual = "3.42.0" truezip = "6.8.4" auto-value = "1.10.4" findbugs = "3.0.2" @@ -43,14 +43,14 @@ serverlib = "2.3.4" ## Internal text-adapter = "3.0.6" text = "3.0.4" -piston = "0.5.7" +piston = "0.5.8" # Tests -mockito = "5.6.0" +mockito = "5.11.0" # Gradle plugins pluginyml = "0.6.0" -minotaur = "2.8.4" +minotaur = "2.8.7" [libraries] # Minecraft expectations diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c4..e6441136f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f..b82aa23a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..7101f8e46 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle.kts b/settings.gradle.kts index 4c6995e2e..74cba1396 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit" include("worldedit-libs") -listOf("legacy", "1_17_1", "1_18_2", "1_19_4", "1_20", "1_20_2").forEach { +listOf("1_18_2", "1_19_4", "1_20", "1_20_2", "1_20_4").forEach { include("worldedit-bukkit:adapters:adapter-$it") } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java deleted file mode 100644 index c9d5ed124..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; - -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("x", "b")); - fieldBitMask = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("z", "c")); - fieldHeightMap = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("availableSections", "d")); - fieldChunkData = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("biomes", "f")); - fieldBlockEntities = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("buffer", "g")); - fieldFull = ClientboundLevelChunkPacket.class.getDeclaredField(Refraction.pickName("blockEntitiesTags", "h")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} 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 deleted file mode 100644 index 16dfd7bd8..000000000 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,526 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; - -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.configuration.Settings; -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.internal.util.LogManagerCompat; -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.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; -import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; -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.server.level.TicketType; -import net.minecraft.util.BitStorage; -import net.minecraft.util.Unit; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.npc.AbstractVillager; -import net.minecraft.world.item.trading.MerchantOffers; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.biome.Biome; -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.chunk.ChunkBiomeContainer; -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.gameevent.GameEventDispatcher; -import net.minecraft.world.level.gameevent.GameEventListener; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import sun.misc.Unsafe; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; -import java.util.stream.Stream; - -public final class PaperweightPlatformAdapter extends NMSAdapter { - - public static final Field fieldStorage; - public static final Field fieldPalette; - public static final Field fieldBits; - - public static final Field fieldBitsPerEntry; - - private static final Field fieldTickingFluidContent; - private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; - - private static final Field fieldBiomes; - - private static final MethodHandle methodGetVisibleChunk; - - private static final Field fieldLock; - - private static final Field fieldGameEventDispatcherSections; - private static final MethodHandle methodremoveBlockEntityTicker; - - private static final Field fieldOffers; - private static final MerchantOffers OFFERS = new MerchantOffers(); - - private static final Field fieldRemove; - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - static { - try { - fieldBits = PalettedContainer.class.getDeclaredField(Refraction.pickName("bits", "l")); - fieldBits.setAccessible(true); - fieldStorage = PalettedContainer.class.getDeclaredField(Refraction.pickName("storage", "c")); - fieldStorage.setAccessible(true); - fieldPalette = PalettedContainer.class.getDeclaredField(Refraction.pickName("palette", "k")); - fieldPalette.setAccessible(true); - - fieldBitsPerEntry = BitStorage.class.getDeclaredField(Refraction.pickName("bits", "c")); - fieldBitsPerEntry.setAccessible(true); - - fieldTickingFluidContent = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); - fieldTickingFluidContent.setAccessible(true); - fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); - - fieldBiomes = ChunkBiomeContainer.class.getDeclaredField(Refraction.pickName("biomes", "f")); - fieldBiomes.setAccessible(true); - - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( - "getVisibleChunkIfPresent", - "getVisibleChunk" - ), long.class); - getVisibleChunkIfPresent.setAccessible(true); - methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - - if (!PaperLib.isPaper()) { - fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); - fieldLock.setAccessible(true); - } else { - // in paper, the used methods are synchronized properly - fieldLock = null; - } - - fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( - "gameEventDispatcherSections", "x")); - fieldGameEventDispatcherSections.setAccessible(true); - Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( - Refraction.pickName( - "removeBlockEntityTicker", - "l" - ), BlockPos.class - ); - removeBlockEntityTicker.setAccessible(true); - methodremoveBlockEntityTicker = MethodHandles.lookup().unreflect(removeBlockEntityTicker); - - fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); - fieldRemove.setAccessible(true); - - fieldOffers = AbstractVillager.class.getDeclaredField(Refraction.pickName("offers", "bU")); - fieldOffers.setAccessible(true); - } 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 - ) { - if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.compareAndSet(sections, expected, value, layer); - } - return false; - } - - // There is no point in having a functional semaphore for paper servers. - private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = - ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); - - static DelegateSemaphore applyLock(LevelChunkSection section) { - if (PaperLib.isPaper()) { - return SEMAPHORE_THREAD_LOCAL.get(); - } - try { - synchronized (section) { - PalettedContainer blocks = section.getStates(); - Semaphore currentLock = (Semaphore) fieldLock.get(blocks); - if (currentLock instanceof DelegateSemaphore delegateSemaphore) { - return delegateSemaphore; - } - DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - fieldLock.set(blocks, 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) { - addTicket(serverLevel, chunkX, chunkZ); - return nmsChunk; - } - nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (nmsChunk != null) { - addTicket(serverLevel, chunkX, chunkZ); - 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; - try { - chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); - } catch (TimeoutException e) { - String world = serverLevel.getWorld().getName(); - // We've already taken 10 seconds we can afford to wait a little here. - boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); - if (loaded) { - LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); - // Retry chunk load - chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); - } else { - throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); - } - } - return chunk.getHandle(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); - } - - private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { - // Ensure chunk is definitely loaded before applying a ticket - net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel - .getChunkSource() - .addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); - } - - 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); - } - } - - @SuppressWarnings("unchecked") - 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(() -> { - ClientboundLevelChunkPacket chunkPacket = new ClientboundLevelChunkPacket(levelChunk); - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(chunkPacket)); - if (lighting) { - //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - boolean trustEdges = true; - ClientboundLightUpdatePacket packet = - new ClientboundLightUpdatePacket(coordIntPair, nmsWorld.getChunkSource().getLightEngine(), null, null, - trustEdges - ); - nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); - } - }); - } - - private static Stream 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 - ) { - return newChunkSection(layer, null, blocks, fastMode, adapter); - } - - public static LevelChunkSection newChunkSection( - final int layer, - final Function get, - char[] set, - boolean fastMode, - CachedBukkitAdapter adapter - ) { - if (set == null) { - return newChunkSection(layer); - } - 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; - final short[] nonEmptyBlockCount = fastMode ? new short[1] : null; - if (get == null) { - num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, nonEmptyBlockCount); - } else { - num_palette = createPalette( - layer, - blockToPalette, - paletteToBlock, - blocksCopy, - get, - set, - adapter, - nonEmptyBlockCount - ); - } - // BlockStates - int bitsPerEntry = MathMan.log2nlz(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 - } - if (bitsPerEntry > 8) { - bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1); - } - - final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry); - 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(bitsPerEntry, 4096, blockStates); - bitArray.fromRaw(blocksCopy); - } - - LevelChunkSection levelChunkSection = newChunkSection(layer); - // set palette & data bits - final PalettedContainer dataPaletteBlocks = - levelChunkSection.getStates(); - // private DataPalette h; - // protected DataBits a; - final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd); - final BitStorage nmsBits = new BitStorage(bitsPerEntry, 4096, bits); - final Palette blockStatePalettedContainer; - if (bitsPerEntry <= 4) { - blockStatePalettedContainer = new LinearPalette<>(Block.BLOCK_STATE_REGISTRY, bitsPerEntry, dataPaletteBlocks, - NbtUtils::readBlockState - ); - } else if (bitsPerEntry < 9) { - blockStatePalettedContainer = new HashMapPalette<>( - Block.BLOCK_STATE_REGISTRY, - bitsPerEntry, - dataPaletteBlocks, - NbtUtils::readBlockState, - NbtUtils::writeBlockState - ); - } else { - blockStatePalettedContainer = LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE; - } - - // set palette if required - if (bitsPerEntry < 9) { - for (int i = 0; i < num_palette; i++) { - final int ordinal = paletteToBlock[i]; - blockToPalette[ordinal] = Integer.MAX_VALUE; - final BlockState state = BlockTypesCache.states[ordinal]; - final net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState(); - blockStatePalettedContainer.idFor(blockState); - } - } - try { - fieldStorage.set(dataPaletteBlocks, nmsBits); - fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer); - fieldBits.set(dataPaletteBlocks, bitsPerEntry); - } catch (final IllegalAccessException e) { - throw new RuntimeException(e); - } - - if (!fastMode) { - levelChunkSection.recalcBlockCounts(); - } else { - try { - fieldNonEmptyBlockCount.set(levelChunkSection, nonEmptyBlockCount[0]); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - return levelChunkSection; - } catch (final Throwable e) { - throw e; - } finally { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - Arrays.fill(paletteToBlock, Integer.MAX_VALUE); - Arrays.fill(blockStates, 0); - Arrays.fill(blocksCopy, 0); - } - } - - private static LevelChunkSection newChunkSection(int layer) { - return new LevelChunkSection(layer); - } - - public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { - fieldTickingFluidContent.setShort(section, (short) 0); - fieldTickingBlockCount.setShort(section, (short) 0); - } - - public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) { - try { - return (Biome[]) fieldBiomes.get(chunkBiomeContainer); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } - - 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)); - } - - @SuppressWarnings("unchecked") - static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { - try { - // Do the method ourselves to avoid trying to reflect generic method parameters - 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); - } - } - methodremoveBlockEntityTicker.invoke(levelChunk, beacon.getBlockPos()); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - static List getEntities(LevelChunk chunk) { - return chunk.level.entityManager.getEntities(chunk.getPos()); - } - - public static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { - boolean isVillager = entity instanceof AbstractVillager && !Fawe.isMainThread(); - boolean unset = false; - if (isVillager) { - try { - if (fieldOffers.get(entity) != null) { - fieldOffers.set(entity, OFFERS); - unset = true; - } - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to villager to avoid async catcher.", e); - } - } - entity.save(compoundTag); - if (unset) { - try { - fieldOffers.set(entity, null); - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to set offers field to null again on villager.", e); - } - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts index f7f40ce66..3713af207 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_18_2/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.18.2-R0.1-SNAPSHOT the().paperDevBundle("1.18.2-R0.1-20220920.010157-167") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java index 49125529d..8b96e2ea6 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,16 +9,13 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; 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_R2.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; @@ -39,7 +35,6 @@ 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; @@ -80,14 +75,12 @@ 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.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); @@ -235,11 +227,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -255,12 +246,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -337,10 +327,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -485,7 +472,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && map.wasAccessibleSinceLastSave()) { // PlayerChunk.d players = map.players; @@ -522,7 +509,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -538,54 +525,33 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @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(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.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()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @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); + getServerLevel(world).entityManager.getEntityGetter().getAll().forEach(mcEntities::add); List list = new ArrayList<>(); mcEntities.forEach((mcEnt) -> { diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 81580910c..7291c0f69 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -153,6 +153,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts index df27ae5d6..e53d2497e 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts @@ -11,6 +11,7 @@ repositories { } dependencies { + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.19.4-R0.1-SNAPSHOT the().paperDevBundle("1.19.4-R0.1-20230608.201059-104") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java index 82aba5fb6..82b13843b 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; 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.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; @@ -38,7 +34,6 @@ 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; @@ -77,13 +72,11 @@ import net.minecraft.world.level.chunk.LevelChunk; 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.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -244,11 +236,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -264,12 +255,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -298,10 +288,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -446,7 +433,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -484,7 +471,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -501,47 +488,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @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(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.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()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 60695c1e8..63bdb5997 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -156,6 +156,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts index 20bff7359..51438592a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.1-R0.1-20230916.212543-167") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.1-R0.1-SNAPSHOT + the().paperDevBundle("1.20.1-R0.1-20230921.165944-178") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java index aad40c611..e13ff700f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; 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.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; @@ -38,7 +34,6 @@ 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; @@ -77,13 +72,11 @@ import net.minecraft.world.level.chunk.LevelChunk; 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.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; @@ -111,8 +104,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -244,11 +236,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -264,12 +255,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -298,10 +288,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -446,7 +433,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -484,7 +471,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -501,47 +488,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @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(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.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()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index 67bcd6902..5f74d1073 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -156,6 +156,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts index 2f525f245..995446059 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_2/build.gradle.kts @@ -11,7 +11,7 @@ repositories { } dependencies { - // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.20.2-R0.1-20231029.153906-63") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.2-R0.1-SNAPSHOT + the().paperDevBundle("1.20.2-R0.1-20231203.034718-121") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 48bc935cb..851de9a0b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,15 +9,12 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; 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.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen.PaperweightRegen; @@ -37,7 +33,6 @@ 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; @@ -76,13 +71,11 @@ import net.minecraft.world.level.chunk.LevelChunk; 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.World; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; @@ -110,8 +103,7 @@ import java.util.stream.Stream; import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -247,11 +239,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -267,12 +258,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -301,10 +291,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -449,7 +436,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; @@ -487,7 +474,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -504,47 +491,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } @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(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.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()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + } + + @Override + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } + + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index d51d31500..1531358fb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -135,6 +135,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts similarity index 56% rename from worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts rename to worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 24c121c3f..d55d44a76 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -1,26 +1,17 @@ import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension -applyPaperweightAdapterConfiguration() - plugins { java } +applyPaperweightAdapterConfiguration() + repositories { - mavenCentral() gradlePluginPortal() } -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(17)) -} - -configurations.all { - attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) -} - - dependencies { - the().paperDevBundle("1.17.1-R0.1-20220414.034903-210") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT + the().paperDevBundle("1.20.4-R0.1-20240325.123556-143") 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java similarity index 82% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightAdapter.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 1b012fe1c..5303dbb77 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -17,28 +17,23 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; -import com.google.common.base.Preconditions; 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.Lifecycle; -import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; 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.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -85,7 +80,9 @@ 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.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -111,14 +108,14 @@ 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.ChunkBiomeContainer; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -127,20 +124,19 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.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; @@ -159,21 +155,21 @@ import java.util.Set; import java.util.TreeMap; 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 javax.annotation.Nullable; 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 Logger logger = Logger.getLogger(getClass().getCanonicalName()); - private final Field worldsField; - private final Method getChunkFutureMainThreadMethod; - private final Field mainThreadProcessorField; + private final Field serverWorldsField; + private final Method getChunkFutureMethod; + private final Field chunkProviderExecutorField; private final Watchdog watchdog; // ------------------------------------------------------------------------ @@ -185,24 +181,25 @@ 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); + 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()); @@ -357,21 +344,19 @@ public final class PaperweightAdapter implements BukkitImplAdapter> biomeTypeToNMSCache = new HashMap<>(); + private static final HashMap, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); + @Override public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess( - this, - new WeakReference<>(((CraftWorld) world).getHandle()) - ); + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } private static net.minecraft.core.Direction adapt(Direction face) { @@ -431,16 +416,19 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) ); - //FAWE end } @Nullable @@ -455,9 +443,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { @Override public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { @@ -503,7 +507,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + )); } @Override public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().networkManager.send(new ClientboundEntityEventPacket( + ((CraftPlayer) player).getHandle().connection.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()); + ItemStack stack = new ItemStack( + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), + item.getAmount() + ); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); return CraftItemStack.asCraftMirror(stack); } @@ -555,7 +568,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter worldDimKey = getWorldDimKey(env); try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() .getWorldData().overworldData(); - WorldGenSettings originalOpts = levelProperties.worldGenSettings(); + WorldOptions originalOpts = levelProperties.worldGenOptions(); long seed = options.getSeed().orElse(originalWorld.getSeed()); - WorldGenSettings newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) + WorldOptions newOpts = options.getSeed().isPresent() + ? originalOpts.withSeed(OptionalLong.of(seed)) : originalOpts; LevelSettings newWorldSettings = new LevelSettings( @@ -647,23 +653,35 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) worldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -683,7 +701,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> chunkLoadings = submitChunkLoadTasks(region, serverWorld); BlockableEventLoop executor; try { - executor = (BlockableEventLoop) mainThreadProcessorField.get(serverWorld.getChunkSource()); + executor = (BlockableEventLoop) chunkProviderExecutorField.get(serverWorld.getChunkSource()); } catch (IllegalAccessException e) { throw new IllegalStateException("Couldn't get executor for chunk loading.", e); } @@ -721,27 +738,20 @@ public final class PaperweightAdapter implements BukkitImplAdapter state = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()).adapt(blockData); + int internalId = Block.getId(blockData); + BlockStateHolder state = BlockStateIdAccess.getBlockStateById(internalId); Objects.requireNonNull(state); BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - blockEntity.save(tag); - //FAWE start - BinaryTag + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); - //FAWE end } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { - ChunkBiomeContainer biomeIndex = chunk.getBiomes(); - if (biomeIndex != null) { - Biome origBiome = biomeIndex.getNoiseBiome(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); - BiomeType adaptedBiome = adapt(serverWorld, origBiome); - if (adaptedBiome != null) { - extent.setBiome(vec, adaptedBiome); - } + Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); + BiomeType adaptedBiome = adapt(serverWorld, origBiome); + if (adaptedBiome != null) { + extent.setBiome(vec, adaptedBiome); } } } @@ -754,9 +764,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) + getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { @@ -815,7 +826,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter values = ListBinaryTag.builder(); + ListBinaryTag.Builder values = ListBinaryTag.builder(); for (net.minecraft.nbt.Tag tag : foreign) { values.add(toNativeBinary(tag)); @@ -913,8 +923,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter. */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -29,17 +29,18 @@ 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; 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.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter; 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; @@ -49,7 +50,6 @@ 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; @@ -63,20 +63,21 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; import java.util.stream.Collectors; +import javax.annotation.Nullable; /** * 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 { +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { //FAWE start - BinaryTag @SuppressWarnings("unchecked") @@ -120,12 +121,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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(); + net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); return nbtToState(fixed); } @@ -135,11 +131,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); sb.append(']'); } return sb.toString(); @@ -182,7 +174,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static final NbtOps OPS_NBT = NbtOps.INSTANCE; private static final int LEGACY_VERSION = 1343; private static int DATA_VERSION; - static PaperweightDataConverters INSTANCE; + public static PaperweightDataConverters INSTANCE; private final Map> converters = new EnumMap<>(LegacyType.class); private final Map> inspectors = new EnumMap<>(LegacyType.class); @@ -213,7 +205,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } } - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { + public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { super(dataVersion); DATA_VERSION = dataVersion; INSTANCE = this; @@ -225,13 +217,17 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo // Called after fixers are built and ready for FIXING @Override - public DataFixer build(final Executor executor) { + public DataFixer buildUnoptimized() { return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); } + @Override + public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { + return buildUnoptimized(); + } + @SuppressWarnings("unchecked") private class WrappedDataFixer implements DataFixer { - private final DataFixer realFixer; WrappedDataFixer(DataFixer realFixer) { @@ -252,12 +248,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return realFixer.update(type, dynamic, sourceVer, targetVer); } - private net.minecraft.nbt.CompoundTag convert( - LegacyType type, - net.minecraft.nbt.CompoundTag cmp, - int sourceVer, - int desiredVersion - ) { + 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) { @@ -282,7 +273,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo public Schema getSchema(int i) { return realFixer.getSchema(i); } - } public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { @@ -293,12 +283,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return convert(type.getDFUType(), cmp, sourceVer); } - public static net.minecraft.nbt.CompoundTag convert( - LegacyType type, - net.minecraft.nbt.CompoundTag cmp, - int sourceVer, - int targetVer - ) { + 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); } @@ -311,25 +296,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 - ) { + 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(); + 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 { @@ -337,7 +313,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo int getDataVersion(); net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); - } @@ -615,13 +590,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return key; } - private static void convertCompound( - LegacyType type, - net.minecraft.nbt.CompoundTag cmp, - String key, - int sourceVer, - int targetVer - ) { + 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)); } @@ -697,7 +666,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorBlockEntity implements DataInspector { @@ -844,8 +812,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataInspectorEntity implements DataInspector { - private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class); - DataInspectorEntity() { } @@ -880,7 +846,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } @@ -900,12 +865,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - abstract net.minecraft.nbt.CompoundTag inspectChecked( - net.minecraft.nbt.CompoundTag nbttagcompound, - int sourceVer, - int targetVer - ); - + abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); } private static class DataInspectorItemList extends DataInspectorTagged { @@ -924,7 +884,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return nbttagcompound; } - } private static class DataInspectorItem extends DataInspectorTagged { @@ -943,7 +902,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return nbttagcompound; } - } private static class DataConverterMaterialId implements DataConverter { @@ -1344,7 +1302,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBanner implements DataConverter { @@ -1391,7 +1348,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterPotionId implements DataConverter { @@ -1669,15 +1625,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataConverterMinecart implements DataConverter { - private static final List a = Lists.newArrayList( - "MinecartRideable", - "MinecartChest", - "MinecartFurnace", - "MinecartTNT", - "MinecartSpawner", - "MinecartHopper", - "MinecartCommandBlock" - ); + private static final List a = Lists.newArrayList("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"); DataConverterMinecart() { } @@ -1701,7 +1649,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterMobSpawner implements DataConverter { @@ -1746,7 +1693,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } } - } private static class DataConverterUUID implements DataConverter { @@ -1765,47 +1711,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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" - ); + 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() { } @@ -1834,7 +1744,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterSaddle implements DataConverter { @@ -1859,7 +1768,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterHanging implements DataConverter { @@ -1898,7 +1806,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterDropChances implements DataConverter { @@ -1922,15 +1829,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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) { + 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 { @@ -1966,7 +1871,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo nbttagcompound.remove("Riding"); return nbttagcompound1; } - } private static class DataConverterBook implements DataConverter { @@ -1991,12 +1895,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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); + object = Component.literal(s); } else { try { object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); if (object == null) { - object = new TextComponent(""); + object = Component.literal(""); } } catch (JsonParseException jsonparseexception) { ; @@ -2019,11 +1923,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } if (object == null) { - object = new TextComponent(s); + object = Component.literal(s); } } } else { - object = new TextComponent(""); + object = Component.literal(""); } nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); @@ -2035,7 +1939,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterCookedFish implements DataConverter { @@ -2056,7 +1959,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterZombie implements DataConverter { @@ -2099,7 +2001,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private int convert(int i) { return i >= 0 && i < 6 ? i : -1; } - } private static class DataConverterVBO implements DataConverter { @@ -2115,7 +2016,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo cmp.putString("useVbo", "true"); return cmp; } - } private static class DataConverterGuardian implements DataConverter { @@ -2138,7 +2038,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterSkeleton implements DataConverter { @@ -2167,7 +2066,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterZombieType implements DataConverter { @@ -2206,7 +2104,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterHorse implements DataConverter { @@ -2249,7 +2146,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterTileEntity implements DataConverter { @@ -2412,8 +2308,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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)) { + 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)) { @@ -2427,7 +2322,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterShulker implements DataConverter { @@ -2446,12 +2340,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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"}; + 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() { } @@ -2488,7 +2381,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterShulkerBoxBlock implements DataConverter { @@ -2507,7 +2399,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterLang implements DataConverter { @@ -2526,7 +2417,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterTotem implements DataConverter { @@ -2545,7 +2435,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBedBlock implements DataConverter { @@ -2593,7 +2482,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataConverterBedItem implements DataConverter { @@ -2612,16 +2500,14 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 { + MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { if (jsonelement.isJsonPrimitive()) { - return new TextComponent(jsonelement.getAsString()); + return Component.literal(jsonelement.getAsString()); } else if (jsonelement.isJsonArray()) { JsonArray jsonarray = jsonelement.getAsJsonArray(); MutableComponent ichatbasecomponent = null; @@ -2629,11 +2515,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo while (iterator.hasNext()) { JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a( - jsonelement1, - jsonelement1.getClass(), - jsondeserializationcontext - ); + MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); if (ichatbasecomponent == null) { ichatbasecomponent = ichatbasecomponent1; @@ -2648,11 +2530,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } } - public Object deserialize( - JsonElement jsonelement, - Type type, - JsonDeserializationContext jsondeserializationcontext - ) throws JsonParseException { + public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { return this.a(jsonelement, type, jsondeserializationcontext); } }).create(); @@ -2681,12 +2559,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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); + object = Component.literal(s1); } else { try { object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); if (object == null) { - object = new TextComponent(""); + object = Component.literal(""); } } catch (JsonParseException jsonparseexception) { ; @@ -2709,20 +2587,18 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } if (object == null) { - object = new TextComponent(s1); + object = Component.literal(s1); } } } else { - object = new TextComponent(""); + object = Component.literal(""); } 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)) { @@ -2735,11 +2611,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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)) { @@ -2748,11 +2622,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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; @@ -2783,11 +2655,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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)) { @@ -2799,15 +2669,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 - ) - ); + nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); } } @@ -2815,26 +2677,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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 - ) - ); + 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)) { @@ -2847,11 +2699,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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); @@ -2866,11 +2716,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorVillagers implements DataInspector { - ResourceLocation entityVillager = getKey("EntityVillager"); @Override @@ -2894,11 +2742,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorMobSpawnerMinecart implements DataInspector { - ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @@ -2913,11 +2759,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorMobSpawnerMobs implements DataInspector { - ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @Override @@ -2938,11 +2782,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } private static class DataInspectorCommandBlock implements DataInspector { - ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); @Override @@ -2955,7 +2797,5 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - } - } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java similarity index 78% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java index 9f081b05e..c27f4a59a 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightFakePlayer.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java @@ -17,18 +17,19 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; 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.ClientInformation; 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.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.phys.Vec3; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @@ -37,15 +38,14 @@ 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 GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); + private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false + ); PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); } @Override @@ -72,17 +72,13 @@ class PaperweightFakePlayer extends ServerPlayer { } @Override - public void updateOptions(ServerboundClientInformationPacket packet) { + public void updateOptions(ClientInformation clientOptions) { } @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) { } @@ -97,7 +93,6 @@ class PaperweightFakePlayer extends ServerPlayer { } @Override - public void openTextEdit(SignBlockEntity sign) { + public void openTextEdit(SignBlockEntity sign, boolean front) { } - } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java similarity index 75% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java index 701e40b12..b50ead936 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/PaperweightWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -27,21 +27,19 @@ 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.FullChunkStatus; 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_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; -import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; +import javax.annotation.Nullable; -public class PaperweightWorldNativeAccess implements - WorldNativeAccess { - +public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; private static final int NOTIFY = 2; @@ -83,19 +81,12 @@ public class PaperweightWorldNativeAccess implements @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.setType(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); + 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 - ) { + 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); } @@ -115,12 +106,7 @@ public class PaperweightWorldNativeAccess implements } @Override - public void notifyBlockUpdate( - LevelChunk chunk, - BlockPos position, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + 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); } @@ -128,7 +114,7 @@ public class PaperweightWorldNativeAccess implements @Override public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); + return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING); } @Override @@ -139,11 +125,7 @@ public class PaperweightWorldNativeAccess implements } @Override - public void notifyNeighbors( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + 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()); @@ -162,27 +144,21 @@ public class PaperweightWorldNativeAccess implements } } + // Not sure why neighborChanged is deprecated + @SuppressWarnings("deprecation") 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 - ) { + 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) - ); + BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); world.getCraftServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; @@ -193,11 +169,7 @@ public class PaperweightWorldNativeAccess implements } @Override - public void onBlockStateChange( - BlockPos pos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { + 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); } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java similarity index 71% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java index aac664459..74b1c035c 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightBlockMaterial.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightBlockMaterial.java @@ -1,28 +1,23 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; 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_17_R1_2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.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.Fluids; import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.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; @@ -35,14 +30,8 @@ public class PaperweightBlockMaterial implements BlockMaterial { 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, @@ -50,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { ); tile = tileEntity == null ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(() -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); + : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); } public Block getBlock() { @@ -65,10 +54,6 @@ public class PaperweightBlockMaterial implements BlockMaterial { return craftBlockData; } - public Material getMaterial() { - return material; - } - @Override public boolean isAir() { return blockState.isAir(); @@ -81,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isOpaque() { - return material.isSolidBlocking(); + return blockState.canOcclude(); } @Override @@ -91,12 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isLiquid() { - return material.isLiquid(); + return !blockState.getFluidState().is(Fluids.EMPTY); } @Override public boolean isSolid() { - return material.isSolid(); + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); } @Override @@ -126,12 +112,12 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; + return blockState.getPistonPushReaction() == PushReaction.DESTROY; } @Override public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; + return blockState.getPistonPushReaction() == PushReaction.BLOCK; } @Override @@ -141,12 +127,12 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isMovementBlocker() { - return material.isSolid(); + return craftMaterial.isSolid(); } @Override public boolean isBurnable() { - return material.isFlammable(); + return craftMaterial.isBurnable(); } @Override @@ -157,12 +143,12 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); + return blockState.canBeReplaced(); } @Override public boolean isTranslucent() { - return isTranslucent; + return !blockState.canOcclude(); } @Override @@ -183,7 +169,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public int getMapColor() { // rgb field - return material.getColor().col; + return block.defaultMapColor().col; } } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java similarity index 71% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 2029be6f9..4414719b8 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -1,7 +1,6 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; -import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; -import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; +import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; @@ -10,20 +9,15 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; -import com.fastasyncworldedit.core.util.TaskManager; 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.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.regen.PaperweightRegen; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.regen.PaperweightRegen; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -39,7 +33,6 @@ 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; @@ -50,53 +43,51 @@ 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 io.papermc.lib.PaperLib; 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.ClientboundLevelChunkPacket; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; 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.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.World; import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; 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.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -110,12 +101,21 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements - IDelegateBukkitImplAdapter { +import static net.minecraft.core.registries.Registries.BIOME; + +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; - private final PaperweightAdapter parent; + static { + try { + CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave"); + } catch (NoSuchMethodException ignored) { // may not be present in newer paper versions + } + } + + private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter parent; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ @@ -126,7 +126,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements private Map>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter(); } @Nullable @@ -135,12 +135,15 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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; } - @SuppressWarnings("unchecked") private synchronized boolean init() { if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { return false; @@ -227,7 +230,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements } public Block getBlock(BlockType blockType) { - return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); + return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK) + .get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); } @Deprecated @@ -235,11 +239,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -255,12 +258,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements 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(); + final ServerLevel handle = getServerLevel(location.getWorld()); 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); @@ -274,7 +276,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements // Read the NBT data BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); } } @@ -287,67 +289,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements return SideEffectSet.defaults().getSideEffectsToApply(); } - @SuppressWarnings("rawtypes") - 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; - } - if (section == null) { - if (blockState.isAir()) { - return true; - } - levelChunkSections[y4] = section = new LevelChunkSection(y4 << 4); - } - 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()) - ); + return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @Override @@ -363,7 +307,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); @@ -492,9 +436,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); + ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && map.wasAccessibleSinceLastSave()) { + if (map != null && wasAccessibleSinceLastSave(map)) { boolean flag = false; // PlayerChunk.d players = map.players; Stream stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) @@ -504,7 +448,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) .forEach(entityPlayer -> { synchronized (chunkPacket) { - ClientboundLevelChunkPacket nmsPacket = (ClientboundLevelChunkPacket) chunkPacket.getNativePacket(); + ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket(); if (nmsPacket == null) { nmsPacket = mapUtil.create(this, chunkPacket); chunkPacket.setNativePacket(nmsPacket); @@ -530,7 +474,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( - ((CraftWorld) world).getHandle(), + getServerLevel(world), new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) ); } @@ -538,72 +482,35 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { ItemStack stack = new ItemStack( - Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) + .get(ResourceLocation.tryParse(baseItemStack.getType().getId())), baseItemStack.getAmount() ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt()))); + 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(); - final BlockVector3 finalBlockVector = blockVector3; - // Sync to main thread to ensure no clashes occur - Map placed = TaskManager.taskManager().sync(() -> { - serverLevel.captureTreeGeneration = true; - serverLevel.captureBlockStates = true; - try { - if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) { - return null; - } - return ImmutableMap.copyOf(serverLevel.capturedBlockStates); - } finally { - serverLevel.captureBlockStates = false; - serverLevel.captureTreeGeneration = false; - serverLevel.capturedBlockStates.clear(); - } - }); - if (placed == null || placed.isEmpty()) { - return false; - } - for (CraftBlockState craftBlockState : placed.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()) - ); - } - return true; + protected void preCaptureStates(final ServerLevel serverLevel) { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = 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); + protected List getCapturedBlockStatesCopy(final ServerLevel serverLevel) { + return new ArrayList<>(serverLevel.capturedBlockStates.values()); + } - List list = new ArrayList<>(); - mcEntities.forEach((mcEnt) -> { - org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity(); - if (bukkitEntity.isValid()) { - list.add(bukkitEntity); - } + @Override + protected void postCaptureBlockStates(final ServerLevel serverLevel) { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } - }); - return list; + @Override + protected ServerLevel getServerLevel(final World world) { + return ((CraftWorld) world).getHandle(); } @Override @@ -642,7 +549,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements final Registry registry = MinecraftServer .getServer() .registryAccess() - .ownedRegistryOrThrow(Registry.BIOME_REGISTRY); + .registryOrThrow(BIOME); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); Biome biome = registry.get(resourceLocation); return registry.getId(biome); @@ -650,11 +557,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public Iterable getRegisteredBiomes() { - WritableRegistry biomeRegistry = ((CraftServer) Bukkit.getServer()) + WritableRegistry biomeRegistry = (WritableRegistry) ((CraftServer) Bukkit.getServer()) .getServer() .registryAccess() - .ownedRegistryOrThrow( - Registry.BIOME_REGISTRY); + .registryOrThrow(BIOME); List keys = biomeRegistry.stream() .map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); List namespacedKeys = new ArrayList<>(); @@ -670,17 +576,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements @Override public RelighterFactory getRelighterFactory() { - try { - Class.forName("ca.spottedleaf.starlight.light.StarLightEngine"); - if (PaperweightStarlightRelighter.isUsable()) { - return new PaperweightStarlightRelighterFactory(); - } - } catch (ThreadDeath td) { - throw td; - } catch (Throwable ignored) { - + if (PaperLib.isPaper()) { + return new PaperweightStarlightRelighterFactory(); + } else { + return new NMSRelighterFactory(); } - return new NMSRelighterFactory(); } @Override @@ -702,4 +602,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements return new PaperweightPostProcessor(); } + private boolean wasAccessibleSinceLastSave(ChunkHolder holder) { + if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) { + try { + return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder); + } catch (IllegalAccessException | InvocationTargetException ignored) { + // fall-through + } + } + // Papers new chunk system has no related replacement - therefor we assume true. + return true; + } + } 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java similarity index 96% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightFaweWorldNativeAccess.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java index 282a6b505..ad04e7b03 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweWorldNativeAccess.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.math.IntPair; @@ -15,14 +15,14 @@ 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.server.level.FullChunkStatus; 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_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; import javax.annotation.Nullable; @@ -102,7 +102,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess currentTick; if (nextTick || cachedChanges.size() >= 1024) { if (nextTick) { @@ -157,7 +157,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize( - () -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); + tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -101,6 +84,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc private final int maxHeight; private final int minSectionPosition; private final int maxSectionPosition; + private final Registry biomeRegistry; + private final IdMap> biomeHolderIdMap; private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); private final Object sendLock = new Object(); private LevelChunkSection[] sections; @@ -127,6 +112,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc this.maxSectionPosition = maxHeight >> 4; this.skyLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()]; + this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); + this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); } public int getChunkX() { @@ -148,6 +135,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); } this.createCopy = createCopy; + // Increment regardless of whether copy will be created or not to return null from getCopy() return ++this.copyKey; } @@ -212,19 +200,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public BiomeType getBiomeType(int x, int y, int z) { - ChunkBiomeContainer index = getChunk().getBiomes(); - Biome biomes = null; - if (y == -1) { - for (y = serverLevel.getMinBuildHeight(); y < serverLevel.getMaxBuildHeight(); y += 4) { - biomes = index.getNoiseBiome(x >> 2, y >> 2, z >> 2); - if (biomes != null) { - break; - } - } - } else { - biomes = index.getNoiseBiome(x >> 2, y >> 2, z >> 2); - } - return biomes != null ? PaperweightPlatformAdapter.adapt(biomes, serverLevel) : null; + LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; + Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biomes, serverLevel); } @Override @@ -235,10 +213,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (dataLayer != null) { lightUpdate = true; synchronized (dataLayer) { - byte[] bytes = PaperLib.isPaper() ? dataLayer.getIfSet() : dataLayer.getData(); - if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) { - Arrays.fill(bytes, (byte) 0); - } + byte[] bytes = dataLayer.getData(); + Arrays.fill(bytes, (byte) 0); } } if (sky) { @@ -251,10 +227,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (dataLayer1 != null) { lightUpdate = true; synchronized (dataLayer1) { - byte[] bytes = PaperLib.isPaper() ? dataLayer1.getIfSet() : dataLayer1.getData(); - if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) { - Arrays.fill(bytes, (byte) 0); - } + byte[] bytes = dataLayer1.getData(); + Arrays.fill(bytes, (byte) 0); } } } @@ -268,7 +242,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))); + return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); } @Override @@ -297,8 +271,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( LightLayer.BLOCK, sectionPos, - dataLayer, - true + dataLayer ); } skyLight[alayer] = dataLayer; @@ -325,7 +298,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc Arrays.fill(LAYER_COUNT, (byte) 15); dataLayer = new DataLayer(LAYER_COUNT); ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true + dataLayer ); } blockLight[alayer] = dataLayer; @@ -342,7 +315,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); @@ -357,6 +338,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public Set getEntities() { + ensureLoaded(serverLevel, chunkX, chunkZ); List entities = PaperweightPlatformAdapter.getEntities(getChunk()); if (entities.isEmpty()) { return Collections.emptySet(); @@ -393,7 +375,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); + input.save(tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -426,7 +408,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc 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()); @@ -460,18 +441,70 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } + 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()); + } + + if (existingSection == null) { + PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( + biomes[setSectionIndex], + biomeHolderIdMap + ); + LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + new char[4096], + 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 { + setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + } + } + } continue; } - int layer = layerNo - getMinSectionPosition(); - bitMask |= 1 << layer; + bitMask |= 1 << getSectionIndex; // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to // this chunk GET when #updateGet is called. Future dords, please listen this time. @@ -481,16 +514,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc // 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[layer]) { - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(layer, copyArr); - } + synchronized (super.sectionLocks[getSectionIndex]) { LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[layer]; + LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; // Don't attempt to tick section whilst we're editing if (existingSection != null) { PaperweightPlatformAdapter.clearCounts(existingSection); @@ -499,23 +526,53 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } + 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()); + } + } + if (existingSection == null) { - newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter); - if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); + PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + setArr, + adapter, + biomeRegistry, + biomeData + ); + if (PaperweightPlatformAdapter.setSectionAtomic( + levelChunkSections, + null, + newSection, + getSectionIndex + )) { + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); continue; } else { - existingSection = levelChunkSections[layer]; + existingSection = levelChunkSections[getSectionIndex]; if (existingSection == null) { LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - +layer + getSectionIndex ); continue; } } } - //ensure that the server doesn't try to tick the chunksection while we're editing it (again). + //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) PaperweightPlatformAdapter.clearCounts(existingSection); if (PaperLib.isPaper()) { existingSection.tickingList.clear(); @@ -532,10 +589,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc this.levelChunk = nmsChunk; this.sections = null; this.reset(); - } else if (existingSection != getSections(false)[layer]) { - this.sections[layer] = existingSection; + } else if (existingSection != getSections(false)[getSectionIndex]) { + this.sections[getSectionIndex] = existingSection; this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layerNo))) { + } else if (!Arrays.equals( + update(getSectionIndex, new char[4096], true), + loadPrivately(layerNo) + )) { this.reset(layerNo); /*} else if (lock.isModified()) { this.reset(layerNo);*/ @@ -543,56 +603,33 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } finally { sectionLock.writeLock().unlock(); } + + PalettedContainer> biomeData = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + newSection = PaperweightPlatformAdapter.newChunkSection( layerNo, this::loadPrivately, setArr, - fastmode, - adapter + adapter, + biomeRegistry, + biomeData ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, newSection, - layer + getSectionIndex )) { LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - +layer + getSectionIndex ); } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); - } - } - } - } - - // Biomes - BiomeType[][] biomes = set.getBiomes(); - if (biomes != null) { - // set biomes - ChunkBiomeContainer currentBiomes = nmsChunk.getBiomes(); - if (createCopy) { - copy.storeBiomes(currentBiomes); - } - 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); - } - } + updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); } } } @@ -656,7 +693,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); + Entity entity = nmsWorld.getEntities().get(uuid); if (entity != null) { removeEntity(entity); } @@ -705,7 +742,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc entity.load(tag); entity.absMoveTo(x, y, z, yaw, pitch); entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { + if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { LOGGER.warn( "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", id, @@ -768,7 +805,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc // Set Modified nmsChunk.setLightCorrect(true); // Set Modified nmsChunk.mustNotSave = false; - nmsChunk.markUnsaved(); + nmsChunk.setUnsaved(true); // send to player if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { this.send(finalMask, finalLightUpdate); @@ -907,11 +944,18 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc try { lock.acquire(); - final PalettedContainer blocks = section.getStates(); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(blocks); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(blocks); + final PalettedContainer blocks = section.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); + final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - final int bitsPerEntry = (int) PaperweightPlatformAdapter.fieldBitsPerEntry.get(bits); + 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); @@ -964,7 +1008,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } - private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) { + private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { if (ibd == null) { return BlockTypesCache.ReservedIDs.AIR; } else { @@ -1020,8 +1064,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( lightLayer, sectionPos, - dataLayer, - true + dataLayer ); } synchronized (dataLayer) { @@ -1039,6 +1082,49 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } + private PalettedContainer> setBiomesToPalettedContainer( + final BiomeType[][] biomes, + final int sectionIndex, + final PalettedContainerRO> data + ) { + PalettedContainer> biomeData; + if (data instanceof PalettedContainer> palettedContainer) { + biomeData = palettedContainer; + } else { + LOGGER.warn( + "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + + "type {} but got {}", + PalettedContainer.class.getSimpleName(), + data.getClass().getSimpleName() + ); + biomeData = data.recreate(); + } + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return biomeData; + } + for (int y = 0, index = 0; y < 4; y++) { + for (int z = 0; z < 4; z++) { + for (int x = 0; x < 4; x++, index++) { + BiomeType biomeType = sectionBiomes[index]; + if (biomeType == null) { + continue; + } + biomeData.set( + x, + y, + z, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)) + ); + } + } + } + return biomeData; + } + @Override public boolean hasSection(int layer) { layer -= getMinSectionPosition(); @@ -1067,10 +1153,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } LevelChunkSection existing = getSections(true)[layer]; try { - final PalettedContainer blocksExisting = existing.getStates(); + final PalettedContainer blocksExisting = existing.getStates(); + final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - blocksExisting); + dataObject); int paletteSize; if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java similarity index 81% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java index cd9987d79..92d9ec801 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks_Copy.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.queue.IBlocks; @@ -8,18 +8,22 @@ 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_17_R1_2.nbt.PaperweightLazyCompoundTag; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag; +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.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; +import net.minecraft.core.Holder; 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.ChunkBiomeContainer; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.Arrays; @@ -32,6 +36,8 @@ import java.util.concurrent.Future; public class PaperweightGetBlocks_Copy implements IChunkGet { + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private final char[][] blocks; @@ -39,7 +45,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { private final int maxHeight; final ServerLevel serverLevel; final LevelChunk levelChunk; - private ChunkBiomeContainer chunkBiomeContainer; + private PalettedContainer>[] biomes = null; protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; @@ -56,7 +62,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))) + new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) ); } @@ -75,7 +81,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); + entity.save(compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } @@ -136,28 +142,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { return minHeight >> 4; } - protected void storeBiomes(ChunkBiomeContainer chunkBiomeContainer) { - // The to do one line below is pre-paperweight and needs to be revised - // TODO revisit last parameter, BiomeStorage[] *would* be more efficient - this.chunkBiomeContainer = new ChunkBiomeContainer(chunkBiomeContainer.biomeRegistry, serverLevel, - chunkBiomeContainer.writeBiomes() - ); - } - @Override public BiomeType getBiomeType(int x, int y, int z) { - Biome biome = null; - if (y == -1) { - for (y = serverLevel.getMinBuildHeight(); y <= serverLevel.getMaxBuildHeight(); y += 4) { - biome = this.chunkBiomeContainer.getNoiseBiome(x >> 2, y >> 2, z >> 2); - if (biome != null) { - break; - } - } - } else { - biome = this.chunkBiomeContainer.getNoiseBiome(x >> 2, y >> 2, z >> 2); - } - return biome != null ? PaperweightPlatformAdapter.adapt(biome, serverLevel) : null; + Holder biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); + return PaperweightPlatformAdapter.adapt(biome, serverLevel); } @Override @@ -183,6 +171,21 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { blocks[layer] = data; } + protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { + if (biomes == null) { + biomes = new PalettedContainer[getSectionCount()]; + } + if (biomeData instanceof PalettedContainer> palettedContainer) { + biomes[layer] = palettedContainer.copy(); + } else { + LOGGER.error( + "Cannot correctly save biomes to history. Expected class type {} but got {}", + PalettedContainer.class.getSimpleName(), + biomeData.getClass().getSimpleName() + ); + } + } + @Override public BaseBlock getFullBlock(int x, int y, int z) { BlockState state = BlockTypesCache.states[get(x, y, z)]; diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java new file mode 100644 index 000000000..97eecfc56 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightMapChunkUtil.java @@ -0,0 +1,34 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java new file mode 100644 index 000000000..147ec5be7 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -0,0 +1,719 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import com.destroystokyo.paper.util.maplist.EntityList; +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.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +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 io.papermc.paper.world.ChunkEntitySlices; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +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.server.level.TicketType; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ExceptionCollector; +import net.minecraft.util.SimpleBitStorage; +import net.minecraft.util.ThreadingDetector; +import net.minecraft.util.Unit; +import net.minecraft.util.ZeroBitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; +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.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +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.entity.PersistentEntitySectionManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; +import sun.misc.Unsafe; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +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.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +import static java.lang.invoke.MethodType.methodType; +import static net.minecraft.core.registries.Registries.BIOME; + +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; + + private static final Field fieldTickingFluidCount; + private static final Field fieldTickingBlockCount; + private static final Field fieldNonEmptyBlockCount; + + private static final MethodHandle methodGetVisibleChunk; + + private static final Field fieldThreadingDetector; + private static final Field fieldLock; + + private static final MethodHandle methodRemoveGameEventListener; + private static final MethodHandle methodremoveTickingBlockEntity; + + /* + * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java + * and is only needed to support 1.19.4 versions before *and* after this change. + */ + private static final MethodHandle CRAFT_CHUNK_GET_HANDLE; + + private static final Field fieldRemove; + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static final boolean POST_CHUNK_REWRITE; + private static Method PAPER_CHUNK_GEN_ALL_ENTITIES; + private static Field LEVEL_CHUNK_ENTITIES; + private static Field SERVER_LEVEL_ENTITY_MANAGER; + + static { + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + 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", "g")); + fieldTickingFluidCount.setAccessible(true); + fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); + fieldNonEmptyBlockCount.setAccessible(true); + + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( + "getVisibleChunkIfPresent", + "b" + ), long.class); + getVisibleChunkIfPresent.setAccessible(true); + methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); + + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetector.setAccessible(true); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLock.setAccessible(true); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldLock = null; + } + + Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( + Refraction.pickName("removeGameEventListener", "a"), + BlockEntity.class, + ServerLevel.class + ); + removeGameEventListener.setAccessible(true); + methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener); + + Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( + Refraction.pickName( + "removeBlockEntityTicker", + "l" + ), BlockPos.class + ); + removeBlockEntityTicker.setAccessible(true); + methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker); + + fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); + fieldRemove.setAccessible(true); + + boolean chunkRewrite; + try { + ServerLevel.class.getDeclaredMethod("getEntityLookup"); + chunkRewrite = true; + PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities"); + PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true); + } catch (NoSuchMethodException ignored) { + chunkRewrite = false; + } + try { + // Paper - Pre-Chunk-Update + LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities"); + LEVEL_CHUNK_ENTITIES.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + try { + // Non-Paper + SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M")); + SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); + } catch (NoSuchFieldException ignored) { + } + POST_CHUNK_REWRITE = chunkRewrite; + } catch (RuntimeException | Error e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + MethodHandle craftChunkGetHandle; + final MethodType type = methodType(LevelChunk.class); + try { + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type); + } catch (NoSuchMethodException | IllegalAccessException e) { + try { + final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class); + craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType); + craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle; + } + + static boolean setSectionAtomic( + LevelChunkSection[] sections, + LevelChunkSection expected, + LevelChunkSection value, + int layer + ) { + if (layer >= 0 && layer < sections.length) { + return ReflectionUtils.compareAndSet(sections, expected, value, layer); + } + return false; + } + + // There is no point in having a functional semaphore for paper servers. + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = + ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null)); + + static DelegateSemaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } + try { + synchronized (section) { + PalettedContainer blocks = section.getStates(); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); + synchronized (currentThreadingDetector) { + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); + if (currentLock instanceof DelegateSemaphore delegateSemaphore) { + return delegateSemaphore; + } + DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); + fieldLock.set(currentThreadingDetector, 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) { + addTicket(serverLevel, chunkX, chunkZ); + return nmsChunk; + } + nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (nmsChunk != null) { + addTicket(serverLevel, chunkX, chunkZ); + 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; + try { + chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + String world = serverLevel.getWorld().getName(); + // We've already taken 10 seconds we can afford to wait a little here. + boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null); + if (loaded) { + LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world); + // Retry chunk load + chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get(); + } else { + throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); + } + } + addTicket(serverLevel, chunkX, chunkZ); + return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk); + } catch (Throwable e) { + e.printStackTrace(); + } + } + return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); + } + + private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { + // Ensure chunk is definitely loaded before applying a ticket + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel + .getChunkSource() + .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + } + + 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); + } + } + + @SuppressWarnings("deprecation") + 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); + LevelChunk levelChunk; + if (PaperLib.isPaper()) { + // getChunkAtIfLoadedImmediately is paper only + levelChunk = nmsWorld + .getChunkSource() + .getChunkAtIfLoadedImmediately(chunkX, chunkZ); + } else { + levelChunk = ((Optional) ((Either) chunkHolder + .getTickingChunkFuture() // method is not present with new paper chunk system + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) + .orElse(null); + } + if (levelChunk == null) { + return; + } + TaskManager.taskManager().task(() -> { + ClientboundLevelChunkWithLightPacket packet; + if (PaperLib.isPaper()) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + // last false is to not bother with x-ray + ); + } else { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } + 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, + CachedBukkitAdapter adapter, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); + } + + public static LevelChunkSection newChunkSection( + final int layer, + final Function get, + char[] set, + 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; + if (get == null) { + num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); + } else { + num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); + } + + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + 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); + } + 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 + ); + if (biomes == null) { + IdMap> biomeHolderIdMap = biomeRegistry.asHolderIdMap(); + biomes = new PalettedContainer<>( + biomeHolderIdMap, + biomeHolderIdMap.byIdOrThrow(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId( + BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + } + + return new LevelChunkSection(blockStatePalettedContainer, biomes); + } catch (final Throwable e) { + throw e; + } finally { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + Arrays.fill(paletteToBlock, Integer.MAX_VALUE); + Arrays.fill(blockStates, 0); + Arrays.fill(blocksCopy, 0); + } + } + + @SuppressWarnings("deprecation") // Only deprecated in paper + private static LevelChunkSection newChunkSection( + int layer, + Registry biomeRegistry, + @Nullable PalettedContainer> biomes + ) { + if (biomes == null) { + return new LevelChunkSection(biomeRegistry); + } + PalettedContainer dataPaletteBlocks = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES + ); + return new LevelChunkSection(dataPaletteBlocks, biomes); + } + + /** + * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. + */ + public static PalettedContainer> getBiomePalettedContainer( + BiomeType[] biomes, + IdMap> biomeRegistry + ) { + if (biomes == null) { + return null; + } + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + // 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))) { + Holder biome; + if (biomeType == null) { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); + } else { + biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); + } + 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.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), + PalettedContainer.Strategy.SECTION_BIOMES + ); + + 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; + } + Holder biome = biomeRegistry.byId(WorldEditPlugin + .getInstance() + .getBukkitImplAdapter() + .getInternalBiomeId(biomeType)); + if (biome == null) { + continue; + } + biomePalettedContainer.set(x, y, z, biome); + } + } + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return biomePalettedContainer; + } + + public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { + fieldTickingFluidCount.setShort(section, (short) 0); + fieldTickingBlockCount.setShort(section, (short) 0); + } + + public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) { + final Registry biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME); + if (biomeRegistry.getKey(biome.value()) == null) { + return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN + : null; + } + return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); + } + + static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { + try { + if (levelChunk.loaded || levelChunk.level.isClientSide()) { + BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); + if (blockEntity != null) { + if (!levelChunk.level.isClientSide) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + } + fieldRemove.set(beacon, true); + } + } + methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + static List getEntities(LevelChunk chunk) { + ExceptionCollector collector = new ExceptionCollector<>(); + if (PaperLib.isPaper()) { + if (POST_CHUNK_REWRITE) { + try { + //noinspection unchecked + return (List) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ)); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e); + } + } + try { + EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk); + return List.of(entityList.getRawData()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e)); + // fall through + } + } + try { + //noinspection unchecked + return ((PersistentEntitySectionManager) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos()); + } catch (IllegalAccessException e) { + collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e)); + } + collector.throwIfPresent(); + return List.of(); + } + + record FakeIdMapBlock(int size) implements IdMap { + + @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; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + + record FakeIdMapBiome(int size) implements IdMap { + + @Override + public int getId(final Biome entry) { + return 0; + } + + @Nullable + @Override + public Biome byId(final int index) { + return null; + } + + @Nonnull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java similarity index 98% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java index 0833c6ecb..cfd9e2753 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPostProcessor.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPostProcessor.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; @@ -165,7 +165,7 @@ public class PaperweightPostProcessor implements IBatchProcessor { } else { type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; } - serverLevel.getLiquidTicks().scheduleTick( + serverLevel.scheduleTick( position, type, type.getTickDelay(serverLevel) 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java similarity index 58% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighter.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java index ea2afede3..49f02bf8d 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java @@ -1,19 +1,15 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.MCUtil; +import net.minecraft.server.level.ChunkMap; 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 java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -21,31 +17,8 @@ import java.util.function.IntConsumer; public class PaperweightStarlightRelighter extends StarlightRelighter { - private static final MethodHandle RELIGHT; 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 - ) - ); - tmp = MethodHandles.dropReturn(tmp); - } catch (NoSuchMethodException | IllegalAccessException e) { - LOGGER.error("Failed to locate 'relight' method in ThreadedLevelLightEngine. Is everything up to date?", e); - } - RELIGHT = tmp; - } + private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { super(serverLevel, queue); @@ -72,25 +45,15 @@ public class PaperweightStarlightRelighter extends StarlightRelighter coords, Consumer chunkCallback, IntConsumer processCallback ) { try { - 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); + serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); + } catch (Exception e) { + LOGGER.error("Error occurred on relighting", e); } } diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java similarity index 88% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java index 9cd0a1ef8..bf9a4e8df 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightStarlightRelighterFactory.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighterFactory.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; @@ -7,7 +7,7 @@ import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import javax.annotation.Nonnull; @@ -23,4 +23,3 @@ public class PaperweightStarlightRelighterFactory implements RelighterFactory { } } - 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java similarity index 98% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/nbt/PaperweightLazyCompoundTag.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java index 21bc0fe72..9a8a51896 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.LazyCompoundTag; 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java similarity index 56% rename from worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java index 63d93156b..edf9e9f90 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_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/regen/PaperweightRegen.java @@ -1,36 +1,37 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.regen; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.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.Codec; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightGetBlocks; +import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.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 io.papermc.lib.PaperLib; -import net.minecraft.core.MappedRegistry; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.data.worldgen.biome.Biomes; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; 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.ChunkMap; +import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; 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.util.LinearCongruentialGenerator; +import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.util.thread.ProcessorMailbox; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelHeightAccessor; @@ -38,9 +39,9 @@ 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.biome.FixedBiomeSource; -import net.minecraft.world.level.biome.OverworldBiomeSource; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.ProtoChunk; @@ -49,31 +50,24 @@ 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.SimpleRandomSource; -import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.levelgen.WorldOptions; +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.levelgen.synth.ImprovedNoise; -import net.minecraft.world.level.newbiome.area.Area; -import net.minecraft.world.level.newbiome.area.AreaFactory; -import net.minecraft.world.level.newbiome.context.BigContext; -import net.minecraft.world.level.newbiome.layer.Layer; -import net.minecraft.world.level.newbiome.layer.Layers; -import net.minecraft.world.level.newbiome.layer.traits.PixelTransformer; +import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; 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_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; +import org.bukkit.Chunk; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import javax.annotation.Nullable; -import java.io.IOException; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.nio.file.Path; import java.util.Collections; import java.util.LinkedHashMap; @@ -82,23 +76,25 @@ import java.util.Map; import java.util.OptionalLong; import java.util.Random; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; -import java.util.function.LongFunction; import java.util.function.Supplier; -import java.util.stream.Collectors; + +import static net.minecraft.core.registries.Registries.BIOME; public class PaperweightRegen extends Regenerator { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final Field worldsField; + private static final Field serverWorldsField; private static final Field paperConfigField; - private static final Field generateFlatBedrockField; + 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; + private static final Field generatorStructureStateField; + private static final Field ringPositionsField; + private static final Field hasGeneratedPositionsField; //list of chunk stati in correct order without FULL private static final Map chunkStati = new LinkedHashMap<>(); @@ -114,21 +110,21 @@ public class PaperweightRegen extends Regenerator) () -> new ServerLevel( @@ -237,72 +253,79 @@ public class PaperweightRegen extends Regenerator singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) : null; @Override public void tick(BooleanSupplier shouldKeepTicking) { //no ticking } @Override - public Biome getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ); + return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( + biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() + ); } }).get(); freshWorld.noSave = true; removeWorldFromWorldsMap(); newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig); + paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); } - //generator - if (originalChunkProvider.getGenerator() instanceof FlatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = (FlatLevelGeneratorSettings) generatorSettingFlatField.get( - originalChunkProvider.getGenerator()); + ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); + if (originalGenerator instanceof FlatLevelSource flatLevelSource) { + FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator) { - Supplier generatorSettingBaseSupplier = (Supplier) generatorSettingBaseSupplierField - .get(originalChunkProvider.getGenerator()); + } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( + originalGenerator); BiomeSource biomeSource; if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options - .getBiomeType() - .getId()))); + + biomeSource = new FixedBiomeSource( + DedicatedServer.getServer().registryAccess() + .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) + ) + ); } else { - biomeSource = originalChunkProvider.getGenerator().getBiomeSource(); - if (biomeSource instanceof OverworldBiomeSource) { - biomeSource = fastOverworldBiomeSource(biomeSource); - } + biomeSource = originalGenerator.getBiomeSource(); } - chunkGenerator = new NoiseBasedChunkGenerator(biomeSource, seed, generatorSettingBaseSupplier); - } else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator) { - chunkGenerator = (ChunkGenerator) delegateField.get(originalChunkProvider.getGenerator()); + chunkGenerator = new NoiseBasedChunkGenerator( + biomeSource, + generatorSettingBaseSupplier + ); + } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { + chunkGenerator = customChunkGenerator.getDelegate(); } else { - LOGGER.error("Unsupported generator type {}", originalChunkProvider.getGenerator().getClass().getName()); + LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); return false; } if (generator != null) { chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); generateConcurrent = generator.isParallelCapable(); } +// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed freshChunkProvider = new ServerChunkCache( freshWorld, @@ -312,6 +335,7 @@ public class PaperweightRegen extends Regenerator { @@ -329,10 +353,26 @@ public class PaperweightRegen extends Regenerator>> origPositions = + (Map>>) ringPositionsField.get(state); + Map>> copy = new Object2ObjectArrayMap<>( + origPositions); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); + ringPositionsField.set(newState, copy); + hasGeneratedPositionsField.setBoolean(newState, true); + } + } + + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then - structureManager = server.getStructureManager(); - threadedLevelLightEngine = freshChunkProvider.getLightEngine(); + structureTemplateManager = server.getStructureManager(); + threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); return true; } @@ -349,7 +389,7 @@ public class PaperweightRegen extends Regenerator { try { freshChunkProvider.close(false); - } catch (IOException e) { + } catch (Exception e) { throw new RuntimeException(e); } }); @@ -371,9 +411,9 @@ public class PaperweightRegen extends Regenerator blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk())); + TaskManager.taskManager().task(() -> { + final CraftWorld world = freshWorld.getWorld(); + final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); + blockPopulator.populate(world, random, chunk); + }); } @Override @@ -416,7 +460,7 @@ public class PaperweightRegen extends Regenerator { try { - Map map = (Map) worldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException e) { throw new RuntimeException(e); @@ -432,180 +476,6 @@ public class PaperweightRegen extends Regenerator biomeRegistryMojang = (Registry) biomeRegistryField.get(biomeSource); - Registry biomeRegistry; - if (options.hasBiomeType()) { - Biome biome = BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options.getBiomeType().getId())); - biomeRegistry = new MappedRegistry<>( - ResourceKey.createRegistryKey(new ResourceLocation("fawe_biomes")), - Lifecycle.experimental() - ); - ((MappedRegistry) biomeRegistry).registerMapping(0, BuiltinRegistries.BIOME.getResourceKey(biome).get(), biome, - Lifecycle.experimental() - ); - } else { - biomeRegistry = biomeRegistryMojang; - } - - //replace genLayer - AreaFactory factory = (AreaFactory) initAreaFactoryMethod.invoke( - null, - legacyBiomeInitLayer, - largebiomes ? 6 : 4, - 4, - (LongFunction) (salt -> new FastWorldGenContextArea(seed, salt)) - ); - biomeSource = new FastOverworldBiomeSource(biomeRegistry, new FastGenLayer(factory)); - - return biomeSource; - } - - private static class FastOverworldBiomeSource extends BiomeSource { - - private final Registry biomeRegistry; - private final boolean isSingleRegistry; - private final FastGenLayer fastGenLayer; - - public FastOverworldBiomeSource( - Registry biomeRegistry, - FastGenLayer genLayer - ) { - super(biomeRegistry.stream().collect(Collectors.toList())); - this.biomeRegistry = biomeRegistry; - this.isSingleRegistry = biomeRegistry.entrySet().size() == 1; - this.fastGenLayer = genLayer; - } - - @Override - protected Codec codec() { - return OverworldBiomeSource.CODEC; - } - - @Override - public BiomeSource withSeed(final long seed) { - return null; - } - - @Override - public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (this.isSingleRegistry) { - return this.biomeRegistry.byId(0); - } - return this.fastGenLayer.get(this.biomeRegistry, biomeX, biomeZ); - } - - } - - private static class FastWorldGenContextArea implements BigContext { - - private final ConcurrentHashMap sharedAreaMap = new ConcurrentHashMap<>(); - private final ImprovedNoise improvedNoise; - private final long magicrandom; - private final ConcurrentHashMap map = new ConcurrentHashMap<>(); //needed for multithreaded generation - - public FastWorldGenContextArea(long seed, long lconst) { - this.magicrandom = mix(seed, lconst); - this.improvedNoise = new ImprovedNoise(new SimpleRandomSource(seed)); - } - - private static long mix(long seed, long salt) { - long l = LinearCongruentialGenerator.next(salt, salt); - l = LinearCongruentialGenerator.next(l, salt); - l = LinearCongruentialGenerator.next(l, salt); - long m = LinearCongruentialGenerator.next(seed, l); - m = LinearCongruentialGenerator.next(m, l); - m = LinearCongruentialGenerator.next(m, l); - return m; - } - - @Override - public FastAreaLazy createResult(PixelTransformer pixelTransformer) { - return new FastAreaLazy(sharedAreaMap, pixelTransformer); - } - - @Override - public void initRandom(long x, long z) { - long l = this.magicrandom; - l = LinearCongruentialGenerator.next(l, x); - l = LinearCongruentialGenerator.next(l, z); - l = LinearCongruentialGenerator.next(l, x); - l = LinearCongruentialGenerator.next(l, z); - this.map.put(Thread.currentThread().getId(), l); - } - - @Override - public int nextRandom(int y) { - long tid = Thread.currentThread().getId(); - long e = this.map.computeIfAbsent(tid, i -> 0L); - int mod = (int) Math.floorMod(e >> 24L, (long) y); - this.map.put(tid, LinearCongruentialGenerator.next(e, this.magicrandom)); - return mod; - } - - @Override - public ImprovedNoise getBiomeNoise() { - return this.improvedNoise; - } - - } - - private static class FastGenLayer extends Layer { - - private final FastAreaLazy fastAreaLazy; - - public FastGenLayer(AreaFactory factory) { - super(() -> null); - this.fastAreaLazy = factory.make(); - } - - @Override - public Biome get(Registry registry, int x, int z) { - ResourceKey key = Biomes.byId(this.fastAreaLazy.get(x, z)); - if (key == null) { - return registry.get(Biomes.byId(0)); - } - Biome biome = registry.get(key); - if (biome == null) { - return registry.get(Biomes.byId(0)); - } - return biome; - } - - } - - private record FastAreaLazy(ConcurrentHashMap sharedMap, PixelTransformer transformer) implements Area { - - @Override - public int get(int x, int z) { - long zx = ChunkPos.asLong(x, z); - return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z)); - } - - } - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { private RegenNoOpWorldLoadListener() { @@ -636,15 +506,19 @@ public class PaperweightRegen extends Regenerator biomeRegistry, + @Nullable final BlendingData blendingData + ) { + super(pos, upgradeData, world, biomeRegistry, blendingData); } + // avoid warning on paper + // compatibility with spigot - public FastProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor) { - super(pos, upgradeData, levelHeightAccessor); - } public boolean generateFlatBedrock() { return generateFlatBedrock; @@ -673,7 +547,7 @@ public class PaperweightRegen extends Regenerator CompletableFuture.completedFuture(Either.left(c)), accessibleChunks @@ -691,4 +565,26 @@ public class PaperweightRegen extends Regenerator MAILBOX = ProcessorMailbox.create(task -> { + }, "fawe-no-op"); + private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { + }); + + public NoOpLightEngine(final ServerChunkCache chunkProvider) { + super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); + } + + @Override + public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { + return CompletableFuture.completedFuture(chunk); + } + + } + } diff --git a/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts b/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts deleted file mode 100644 index 822c1f70b..000000000 --- a/worldedit-bukkit/adapters/adapter-legacy/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - base -} - -artifacts { - add("default", file("./src/main/resources/fastasyncworldedit-adapters.jar")) -} diff --git a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar b/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar deleted file mode 100644 index 9000989ef..000000000 Binary files a/worldedit-bukkit/adapters/adapter-legacy/src/main/resources/fastasyncworldedit-adapters.jar and /dev/null differ diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index ead334bf4..e02685954 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -141,20 +141,15 @@ tasks.named("jar") { addJarManifest(WorldEditKind.Plugin, includeClasspath = true) tasks.named("shadowJar") { - dependsOn(project.project(":worldedit-bukkit:adapters").subprojects.map { it.tasks.named("assemble") }) - from(Callable { - adapters.resolve() - .map { f -> - zipTree(f).matching { - exclude("META-INF/") - } - } - }) + configurations.add(adapters) archiveFileName.set("${rootProject.name}-Bukkit-${project.version}.${archiveExtension.getOrElse("jar")}") dependencies { // In tandem with not bundling log4j, we shouldn't relocate base package here. // relocate("org.apache.logging", "com.sk89q.worldedit.log4j") relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4") + + exclude(dependency("$group:$name")) + include(dependency(":worldedit-core")) include(dependency(":worldedit-libs:bukkit")) // Purposefully not included, we assume (even though no API exposes it) that Log4J will be present at runtime @@ -183,7 +178,7 @@ tasks.named("shadowJar") { include(dependency("org.lz4:lz4-java:1.8.0")) } relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { - include(dependency("net.kyori:adventure-nbt:4.14.0")) + include(dependency("net.kyori:adventure-nbt:4.16.0")) } relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { include(dependency("com.zaxxer:SparseBitSet:1.3")) @@ -192,6 +187,15 @@ tasks.named("shadowJar") { include(dependency("org.anarres:parallelgzip:1.0.5")) } } + + project.project(":worldedit-bukkit:adapters").subprojects.forEach { + dependencies { + include(dependency("${it.group}:${it.name}")) + } + minimize { + exclude(dependency("${it.group}:${it.name}")) + } + } } tasks.named("assemble").configure { @@ -206,7 +210,7 @@ tasks { versionNumber.set("${project.version}") versionType.set("release") uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) - gameVersions.addAll(listOf("1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1", "1.16.5")) + gameVersions.addAll(listOf("1.20.4", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4", "1.18.2")) loaders.addAll(listOf("paper", "spigot")) changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + "FastAsyncWorldEdit/releases/tag/${project.version}") 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 043b614da..ab36cb562 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/FaweBukkit.java @@ -109,14 +109,6 @@ public class FaweBukkit implements IFawe, Listener { 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?"); } - - if (version.isEqualOrLowerThan(MinecraftVersion.ONE_DOT_SIXTEEN_EOL)) { - LOGGER.warn("You are running Minecraft 1.16.5. This version has been released over two years ago (January 2021)."); - LOGGER.warn("FastAsyncWorldEdit will stop operating on this version in the near future."); - LOGGER.warn("Neither Mojang, nor Spigot or other software vendors support this version anymore." + - "Please update your server to a newer version of Minecraft (1.20+) to continue receiving updates and " + - "support."); - } } @Override diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java new file mode 100644 index 000000000..e116daf17 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/FaweAdapter.java @@ -0,0 +1,72 @@ +package com.fastasyncworldedit.bukkit.adapter; + +import com.fastasyncworldedit.core.util.TaskManager; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.TreeGenerator; +import org.bukkit.Material; +import org.bukkit.TreeType; +import org.bukkit.World; +import org.bukkit.block.BlockState; + +import java.util.List; + +/** + * A base class for version-specific implementations of the BukkitImplAdapter + * + * @param the version-specific NBT tag type + * @param the version-specific ServerLevel type + */ +public abstract class FaweAdapter extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { + + @Override + public boolean generateTree( + final TreeGenerator.TreeType treeType, + final EditSession editSession, + BlockVector3 blockVector3, + final World world + ) { + TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType); + if (bukkitType == TreeType.CHORUS_PLANT) { + // bukkit skips the feature gen which does this offset normally, so we have to add it back + blockVector3 = blockVector3.add(BlockVector3.UNIT_Y); + } + BlockVector3 target = blockVector3; + SERVER_LEVEL serverLevel = getServerLevel(world); + List placed = TaskManager.taskManager().sync(() -> { + preCaptureStates(serverLevel); + try { + if (!world.generateTree(BukkitAdapter.adapt(world, target), bukkitType)) { + return null; + } + return getCapturedBlockStatesCopy(serverLevel); + } finally { + postCaptureBlockStates(serverLevel); + } + }); + + if (placed == null || placed.isEmpty()) { + return false; + } + for (BlockState blockState : placed) { + if (blockState == null || blockState.getType() == Material.AIR) { + continue; + } + editSession.setBlock(blockState.getX(), blockState.getY(), blockState.getZ(), + BukkitAdapter.adapt(blockState.getBlockData()) + ); + } + return true; + } + + protected abstract void preCaptureStates(SERVER_LEVEL serverLevel); + + protected abstract List getCapturedBlockStatesCopy(SERVER_LEVEL serverLevel); + + protected abstract void postCaptureBlockStates(SERVER_LEVEL serverLevel); + + protected abstract SERVER_LEVEL getServerLevel(World world); + +} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java index ade2d8258..1043d9a3e 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java @@ -163,13 +163,22 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { final Location location = player.getLocation(); final Set regions = this.getRegions(localplayer, location, isWhitelist); if (!regions.isEmpty()) { + RegionManager manager = WorldGuard + .getInstance() + .getPlatform() + .getRegionContainer() + .get(BukkitAdapter.adapt(location.getWorld())); + if (manager == null) { + return null; + } Set result = new HashSet<>(); for (ProtectedRegion myRegion : regions) { if (myRegion.getId().equals("__global__")) { return new FaweMask(RegionWrapper.GLOBAL()) { @Override public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { - return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion); + return manager.hasRegion(myRegion.getId()) + && isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion); } }; } else { @@ -185,7 +194,7 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { final LocalPlayer localplayer = worldguard.wrapPlayer(BukkitAdapter.adapt(player)); for (ProtectedRegion myRegion : regions) { - if (!isAllowed(localplayer, myRegion)) { + if (!manager.hasRegion(myRegion.getId()) || !isAllowed(localplayer, myRegion)) { return false; } } 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 4ef1a3d05..c111ff630 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 @@ -16,6 +16,7 @@ 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.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.FlatRegionFunction; @@ -160,6 +161,10 @@ public class FaweDelegateRegionManager { ); editSession.setBlocks(onTop, air); } + + FlatRegionFunction replace = new BiomeReplace(editSession, biome); + FlatRegionVisitor visitor = new FlatRegionVisitor((CuboidRegion) floorRegion, replace, editSession); + Operations.completeLegacy(visitor); } if (hybridPlotWorld.PLOT_SCHEMATIC) { @@ -213,7 +218,6 @@ public class FaweDelegateRegionManager { ) { TaskManager.taskManager().async(() -> { synchronized (FaweDelegateRegionManager.class) { - //todo because of the following code this should probably be in the Bukkit module World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName())); World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName())); EditSession sessionA = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World) @@ -232,14 +236,16 @@ public class FaweDelegateRegionManager { CuboidRegion regionB = new CuboidRegion( pos3World, swapPos.getBlockVector3(), - swapPos.getBlockVector3().add(pos2.getBlockVector3()).subtract(pos1.getBlockVector3()) + swapPos.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3())).withY(pos2.getY()) ); - Clipboard clipA = Clipboard.create(regionA, UUID.randomUUID()); - Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID()); + Clipboard clipA = new BlockArrayClipboard(regionA, UUID.randomUUID()); + Clipboard clipB = new BlockArrayClipboard(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); + copyA.setCopyingEntities(true); + copyB.setCopyingEntities(true); try { Operations.completeLegacy(copyA); Operations.completeLegacy(copyB); @@ -253,17 +259,16 @@ public class FaweDelegateRegionManager { sessionA.close(); sessionB.close(); } - FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null, + FaweAPI.fixLighting( + pos1World, + regionA, + null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); - FaweAPI.fixLighting(pos1World, new CuboidRegion( - swapPos.getBlockVector3(), - BlockVector3.at( - swapPos.getX() + pos2.getX() - pos1.getX(), - 0, - swapPos.getZ() + pos2.getZ() - pos1.getZ() - ) - ), null, + FaweAPI.fixLighting( + pos1World, + regionB, + null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE) ); if (whenDone != 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 f719d430d..08ee52de6 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 @@ -13,7 +13,6 @@ import java.util.regex.Pattern; public class MinecraftVersion implements Comparable { public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16); - public static final MinecraftVersion ONE_DOT_SIXTEEN_EOL = new MinecraftVersion(1, 16, 5); public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17); public static final MinecraftVersion CAVES_18 = new MinecraftVersion(1, 18); private static MinecraftVersion current = null; 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 551e6301e..24a6af78a 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 @@ -307,9 +307,6 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser if (!tickFluid) { return null; } - if (Settings.settings().QUEUE.NO_TICK_FASTMODE && fastMode) { - return null; - } return this.plugin.getBukkitImplAdapter().getTickingPostProcessor(); } 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 a9ba45afe..1598cb547 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 @@ -327,12 +327,12 @@ public class BukkitWorld extends AbstractWorld { treeTypeMapping.put(TreeGenerator.TreeType.RANDOM_MUSHROOM, TreeType.BROWN_MUSHROOM); for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { if (treeTypeMapping.get(type) == null) { - LOGGER.error("No TreeType mapping for TreeGenerator.TreeType." + type); //FAWE start + LOGGER.info("No TreeType mapping for TreeGenerator.TreeType." + type); 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); + " {} is not available. This is not an error. This version of FAWE will work on your version of " + + " Minecraft. This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type); //FAWE end } } diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index b4f845265..cd12b1008 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -21,7 +21,7 @@ permissions: default: op children: fawe.bypass.regions: true - fawe.limit.*: true + fawe.limit.unlimited: true fawe.tips: default: op fawe.admin: diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index 052c772d5..507da7e01 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -245,6 +245,11 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public @Nullable Location getRespawnLocation() { + return null; + } + @Override public void incrementStatistic(@Nonnull Statistic statistic) throws IllegalArgumentException { @@ -365,4 +370,9 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { return null; } + @Override + public @Nullable Location getLocation() { + return null; + } + } 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 0655e4214..46a3a1574 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -612,12 +612,38 @@ public enum FaweCache implements Trimable { /* Thread stuff */ + + /** + * Create a new blocking executor with default name and FaweCache logger + * + * @return new blocking executor + */ public ThreadPoolExecutor newBlockingExecutor() { + return newBlockingExecutor("FAWE Blocking Executor - %d"); + } + + /** + * Create a new blocking executor with specified name and FaweCache logger + * + * @return new blocking executor + * @since 2.9.0 + */ + public ThreadPoolExecutor newBlockingExecutor(String name) { + return newBlockingExecutor(name, LOGGER); + } + + /** + * Create a new blocking executor with specified name and logger + * + * @return new blocking executor + * @since 2.9.0 + */ + public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) { int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS; ArrayBlockingQueue queue = new ArrayBlockingQueue<>(nThreads, true); return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue, - new ThreadFactoryBuilder().setNameFormat("FAWE Blocking Executor - %d").build(), + new ThreadFactoryBuilder().setNameFormat(name).build(), new ThreadPoolExecutor.CallerRunsPolicy() ) { @@ -652,10 +678,10 @@ public enum FaweCache implements Trimable { int hash = throwable.getMessage() != null ? throwable.getMessage().hashCode() : 0; if (hash != lastException) { lastException = hash; - LOGGER.catching(throwable); + logger.catching(throwable); count = 0; } else if (count < Settings.settings().QUEUE.PARALLEL_THREADS) { - LOGGER.warn(throwable.getMessage()); + logger.warn(throwable.getMessage()); count++; } } @@ -665,10 +691,10 @@ public enum FaweCache implements Trimable { private void handleFaweException(FaweException e) { FaweException.Type type = e.getType(); if (e.getType() == FaweException.Type.OTHER) { - LOGGER.catching(e); + logger.catching(e); } else if (!faweExceptionReasonsUsed[type.ordinal()]) { faweExceptionReasonsUsed[type.ordinal()] = true; - LOGGER.warn("FaweException: " + e.getMessage()); + logger.warn("FaweException: " + e.getMessage()); } } }; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java index 13490dc2f..21879751c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/ErodeBrush.java @@ -67,11 +67,11 @@ public class ErodeBrush implements Brush { final int by = target.getBlockY(); final int bz = target.getBlockZ(); - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < buffer1.getWidth(); x++, relx++) { int x0 = x + bx; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < buffer1.getHeight(); y++, rely++) { int y0 = y + by; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < buffer1.getLength(); z++, relz++) { int z0 = z + bz; BlockState state = es.getBlock(x0, y0, z0); buffer1.setBlock(relx, rely, relz, state); @@ -115,11 +115,11 @@ public class ErodeBrush implements Brush { Clipboard current, Clipboard target ) { int[] frequency = null; - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) { int x2 = x * x; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) { int x2y2 = x2 + z * z; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) { int cube = x2y2 + y * y; target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz)); if (cube >= brushSizeSquared) { @@ -166,11 +166,11 @@ public class ErodeBrush implements Brush { Clipboard current, Clipboard target ) { int[] frequency = null; - for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) { + for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) { int x2 = x * x; - for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) { + for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) { int x2y2 = x2 + z * z; - for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) { + for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) { int cube = x2y2 + y * y; target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz)); if (cube >= brushSizeSquared) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java index fea4884f1..2c6ea5ec0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/HeightBrush.java @@ -53,7 +53,7 @@ public class HeightBrush implements Brush { try { heightMap = ScalableHeightMap.fromPNG(stream); } catch (IOException e) { - throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid")); + throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid", e.getMessage())); } } else if (clipboard != null) { heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY); 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 672dcebe8..89f48b697 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 @@ -102,7 +102,7 @@ public class Settings extends Config { public FaweLimit getLimit(Actor actor) { FaweLimit limit; - if (actor.hasPermission("fawe.bypass") || actor.hasPermission("fawe.limit.unlimited")) { + if (actor.hasPermission("fawe.limit.unlimited")) { return FaweLimit.MAX.copy(); } limit = new FaweLimit(); @@ -511,7 +511,7 @@ public class Settings extends Config { " - 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", + " - Values smaller than the configured parallel-threads are not accepted", " - It is recommended this option be at least 4x greater than parallel-threads" }) @@ -544,12 +544,6 @@ public class Settings extends Config { }) public boolean POOL = true; - @Comment({ - "When using fastmode do not bother to tick existing/placed blocks/fluids", - "Only works in versions up to 1.17.1" - }) - public boolean NO_TICK_FASTMODE = true; - public static class PROGRESS { @Comment({"Display constant titles about the progress of a user's edit", @@ -721,6 +715,13 @@ public class Settings extends Config { " - Requires clipboard.use-disk to be enabled" }) public boolean SAVE_CLIPBOARD_NBT_TO_DISK = true; + @Comment({ + "Apply a file lock on the clipboard file (only relevant if clipboad.on-disk is enabled)", + " - Prevents other processes using the file whilst in use by FAWE", + " - This extends to other servers, useful if you have multiple servers using a unified clipboard folder", + " - May run into issues where a file lock is not correctly lifted" + }) + public boolean LOCK_CLIPBOARD_FILE = false; } 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 3624e34c0..1677521fe 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 @@ -159,15 +159,25 @@ public class RollbackDatabase extends AsyncNotifyQueue { Future future = call(() -> { try { int count = 0; - 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)) { + String stmtStr = """ + SELECT * FROM `%sedits` + WHERE `time` > ? + AND `x2` >= ? + AND `x1` <= ? + AND `z2` >= ? + AND `z1` <= ? + AND `y2` >= ? + AND `y1` <= ? + """; + if (uuid != null) { + stmtStr += "\n AND `player`= ?"; + } + if (ascending) { + stmtStr += "\n ORDER BY `time` ASC, `id` ASC"; + } else { + stmtStr += "\n ORDER BY `time` DESC, `id` DESC"; + } + try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) { stmt.setInt(1, (int) (minTime / 1000)); stmt.setInt(2, pos1.getBlockX()); stmt.setInt(3, pos2.getBlockX()); @@ -193,20 +203,20 @@ public class RollbackDatabase extends AsyncNotifyQueue { if (delete && uuid != null) { 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()); - stmt.setInt(4, pos1.getBlockZ()); - stmt.setInt(5, pos2.getBlockZ()); - // Keep 128 offset for backwards-compatibility - stmt.setInt(6, pos1.getBlockY() - 128); - stmt.setInt(7, pos2.getBlockY() - 128); byte[] uuidBytes = ByteBuffer .allocate(16) .putLong(uuid.getMostSignificantBits()) .putLong(uuid.getLeastSignificantBits()) .array(); - stmt.setBytes(8, uuidBytes); + stmt.setBytes(1, uuidBytes); + stmt.setInt(2, (int) (minTime / 1000)); + stmt.setInt(3, pos1.getBlockX()); + stmt.setInt(4, pos2.getBlockX()); + stmt.setInt(5, pos1.getBlockZ()); + stmt.setInt(6, pos2.getBlockZ()); + // Keep 128 offset for backwards-compatibility + stmt.setInt(7, pos1.getBlockY() - 128); + stmt.setInt(8, pos2.getBlockY() - 128); } } return count; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java index 617143495..30dad8f37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/RichParser.java @@ -53,7 +53,7 @@ public abstract class RichParser extends InputParser implements AliasedPar } @Nonnull - private Function> extractArguments(String input) { + private Function> extractArguments(String input, ParserContext context) { return prefix -> { if (input.length() > prefix.length() && input.startsWith(prefix + "[")) { // input already contains argument(s) -> extract them @@ -65,7 +65,7 @@ public abstract class RichParser extends InputParser implements AliasedPar } String previous = prefix + builder; // read the suggestions for the last argument - return getSuggestions(strings[strings.length - 1], strings.length - 1) + return getSuggestions(strings[strings.length - 1], strings.length - 1, context) .map(suggestion -> previous + "[" + suggestion); } else { return Stream.of(prefix); @@ -95,7 +95,7 @@ public abstract class RichParser extends InputParser implements AliasedPar public Stream getSuggestions(String input) { return Arrays.stream(this.prefixes) .filter(validPrefix(input)) - .flatMap(extractArguments(input)); + .flatMap(extractArguments(input, new ParserContext())); } @Override @@ -122,8 +122,25 @@ public abstract class RichParser extends InputParser implements AliasedPar * @param argumentInput the already provided input for the argument at the given index. * @param index the index of the argument to get suggestions for. * @return a stream of suggestions matching the given input for the argument at the given index. + * + * @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, int, ParserContext)} */ - protected abstract Stream getSuggestions(String argumentInput, int index); + @Deprecated + protected Stream getSuggestions(String argumentInput, int index) { + return Stream.empty(); + } + + /** + * Returns a stream of suggestions for the argument at the given index. + * + * @param argumentInput the already provided input for the argument at the given index. + * @param index the index of the argument to get suggestions for. + * @param context the context which may optionally be provided by a parser. + * @return a stream of suggestions matching the given input for the argument at the given index. + */ + protected Stream getSuggestions(String argumentInput, int index, ParserContext context) { + return getSuggestions(argumentInput, index); + } /** * Parses the already split arguments. diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java index 4e0fbfa91..84437c19a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -97,11 +97,11 @@ public class RichMaskParser extends FaweParser { )), () -> { if (full.length() == 1) { - return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); + return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context)); } return new ArrayList<>(worldEdit .getMaskFactory() - .getSuggestions(command.toLowerCase(Locale.ROOT))); + .getSuggestions(command.toLowerCase(Locale.ROOT), context)); } ); } @@ -164,11 +164,11 @@ public class RichMaskParser extends FaweParser { )), () -> { if (full.length() == 1) { - return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); + return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context)); } return new ArrayList<>(worldEdit .getMaskFactory() - .getSuggestions(command.toLowerCase(Locale.ROOT))); + .getSuggestions(command.toLowerCase(Locale.ROOT), context)); } ); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java index 5a310f60a..7da0b2377 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear2DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear2DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear2DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear2DPatternParser extends RichParser { @@ -59,9 +58,8 @@ public class Linear2DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[2]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear2DBlockPattern(patterns.toArray(new Pattern[0]), xScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear2DRandom(xScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java index ef45e8faa..cd3a7d8db 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/Linear3DPatternParser.java @@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.RichParser; -import com.fastasyncworldedit.core.function.pattern.Linear3DBlockPattern; +import com.fastasyncworldedit.core.math.random.Linear3DRandom; import com.google.common.base.Preconditions; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; @@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nonnull; -import java.util.Set; import java.util.stream.Stream; public class Linear3DPatternParser extends RichParser { @@ -64,9 +63,8 @@ public class Linear3DPatternParser extends RichParser { zScale = Integer.parseInt(arguments[3]); Preconditions.checkArgument(zScale != 0); } - if (inner instanceof RandomPattern) { - Set patterns = ((RandomPattern) inner).getPatterns(); - return new Linear3DBlockPattern(patterns.toArray(new Pattern[0]), xScale, yScale, zScale); + if (inner instanceof RandomPattern rp) { + return new RandomPattern(new Linear3DRandom(xScale, yScale, zScale), rp); } throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName() + " cannot be used with " + getPrefix())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java index d7b8a986e..f04412e70 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/BlockTranslateExtent.java @@ -9,7 +9,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public class BlockTranslateExtent extends AbstractDelegateExtent { +public final class BlockTranslateExtent extends AbstractDelegateExtent { private final int dx; private final int dy; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java index f1c523ce3..68307ffe1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/DisallowedBlocksExtent.java @@ -29,7 +29,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IBatchProcessor { +public final class DisallowedBlocksExtent extends AbstractDelegateExtent implements IBatchProcessor { private static final BlockState RESERVED = BlockTypes.__RESERVED__.getDefaultState(); private final Set> remaps; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ExtentHeightCacher.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ExtentHeightCacher.java index af008d1c9..36011e594 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ExtentHeightCacher.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ExtentHeightCacher.java @@ -4,7 +4,7 @@ import com.sk89q.worldedit.extent.Extent; import java.util.Arrays; -public class ExtentHeightCacher extends PassthroughExtent { +public final class ExtentHeightCacher extends PassthroughExtent { private transient int cacheBotX = Integer.MIN_VALUE; private transient int cacheBotZ = Integer.MIN_VALUE; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java index ff57e00da..817d2c3bf 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java @@ -6,14 +6,13 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.regions.RegionWrapper; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import java.util.Collection; import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; -public class HeightBoundExtent extends FaweRegionExtent { +public final class HeightBoundExtent extends FaweRegionExtent { private final int min; private final int max; @@ -50,7 +49,8 @@ public class HeightBoundExtent extends FaweRegionExtent { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - if (trimY(set, min, max, true) | trimNBT(set, this::contains)) { + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + if (trimY(set, min, max, true) | trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)))) { return set; } return null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java index 2fc5133c6..9ac018043 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HistoryExtent.java @@ -25,7 +25,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Stores changes to a {@link ChangeSet}. */ -public class HistoryExtent extends AbstractDelegateExtent { +public final class HistoryExtent extends AbstractDelegateExtent { private final MutableBlockVector3 mutable = new MutableBlockVector3(); private AbstractChangeSet changeSet; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index 942d0ff7b..0aa8023ec 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -37,7 +37,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; -public class LimitExtent extends AbstractDelegateExtent { +public final class LimitExtent extends AbstractDelegateExtent { private final FaweLimit limit; private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; 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 e2d215c56..d33291d1c 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 @@ -8,7 +8,7 @@ import com.fastasyncworldedit.core.util.WEManager; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; -public class MemoryCheckingExtent extends PassthroughExtent { +public final class MemoryCheckingExtent extends PassthroughExtent { private final Actor actor; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java index c13c5965b..9e02dba94 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java @@ -15,7 +15,7 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.Future; -public class MultiRegionExtent extends FaweRegionExtent { +public final class MultiRegionExtent extends FaweRegionExtent { @Nullable private final RegionIntersection intersection; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java index 4f0ad4960..d4c7dc6aa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/NullExtent.java @@ -40,7 +40,7 @@ import java.util.UUID; import java.util.concurrent.Future; //todo This should be removed in favor of com.sk89q.worldedit.extent.NullExtent -public class NullExtent extends FaweRegionExtent implements IBatchProcessor { +public final class NullExtent extends FaweRegionExtent implements IBatchProcessor { private final FaweException reason; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java index 5ac2f9d7b..23f0fa603 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java @@ -26,7 +26,7 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Set; -public class PassthroughExtent extends AbstractDelegateExtent { +public abstract class PassthroughExtent extends AbstractDelegateExtent { /** * Create a new instance. diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java index 6d74acc16..99ef6d137 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PositionTransformExtent.java @@ -11,7 +11,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; -public class PositionTransformExtent extends ResettableExtent { +public final class PositionTransformExtent extends ResettableExtent { private transient MutableBlockVector3 mutable = new MutableBlockVector3(); private transient BlockVector3 min; 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 5abe90348..e9e90e0f8 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 @@ -18,7 +18,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.UUID; -public class ProcessedWEExtent extends AbstractDelegateExtent { +public final class ProcessedWEExtent extends AbstractDelegateExtent { private final FaweLimit limit; private final Extent extent; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java index 0e3798415..469a27c03 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/ResettableExtent.java @@ -14,7 +14,7 @@ import java.lang.reflect.Field; import static com.google.common.base.Preconditions.checkNotNull; -public class ResettableExtent extends AbstractDelegateExtent implements Serializable { +public abstract class ResettableExtent extends AbstractDelegateExtent implements Serializable { public ResettableExtent(Extent parent) { super(parent); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SingleRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SingleRegionExtent.java index 1caea9dbc..249b9e84c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SingleRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SingleRegionExtent.java @@ -11,7 +11,7 @@ import java.util.Collection; import java.util.Collections; import java.util.concurrent.Future; -public class SingleRegionExtent extends FaweRegionExtent { +public final class SingleRegionExtent extends FaweRegionExtent { private final Region region; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SlowExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SlowExtent.java index 6aa07b116..657322ce3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SlowExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SlowExtent.java @@ -6,7 +6,7 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.block.BlockStateHolder; -public class SlowExtent extends AbstractDelegateExtent { +public final class SlowExtent extends AbstractDelegateExtent { private final long THRESHOLD = 50 * 1000000; // 1 tick private final long nanos; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java index 6c2230372..389f5b69f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SourceMaskExtent.java @@ -9,7 +9,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import static com.google.common.base.Preconditions.checkNotNull; -public class SourceMaskExtent extends TemporalExtent { +public final class SourceMaskExtent extends TemporalExtent { private Mask mask; private final MutableBlockVector3 mutable = new MutableBlockVector3(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index ded96d5aa..4d1b287c5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -34,7 +34,7 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor { +public final class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor { private final Set strip; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SupplyingExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SupplyingExtent.java index 640243d5d..96952de4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SupplyingExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/SupplyingExtent.java @@ -7,7 +7,7 @@ import java.util.function.Supplier; /** * An extent that delegates actions to another extent that may change at any time. */ -public class SupplyingExtent extends PassthroughExtent { +public final class SupplyingExtent extends PassthroughExtent { private final Supplier extentSupplier; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java index ac36bef5a..030fcc290 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TemporalExtent.java @@ -8,7 +8,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; -public class TemporalExtent extends PassthroughExtent { +public abstract class TemporalExtent extends PassthroughExtent { private int x; private int y; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java deleted file mode 100644 index 91b99b025..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.fastasyncworldedit.core.extent; - -import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.math.MutableVector3; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.transform.BlockTransformExtent; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -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; - -public class TransformExtent extends BlockTransformExtent { - - private final MutableVector3 mutable1 = new MutableVector3(); - private final MutableBlockVector3 mutable2 = new MutableBlockVector3(); - private BlockVector3 min; - - public TransformExtent(Extent parent) { - super(parent); - } - - @Override - public ResettableExtent setExtent(Extent extent) { - min = null; - return super.setExtent(extent); - } - - @Override - public BlockVector3 getMinimumPoint() { - BlockVector3 pos1 = getPos(super.getMinimumPoint()); - BlockVector3 pos2 = getPos(super.getMaximumPoint()); - return pos1.getMinimum(pos2); - } - - @Override - public BlockVector3 getMaximumPoint() { - BlockVector3 pos1 = getPos(super.getMinimumPoint()); - BlockVector3 pos2 = getPos(super.getMaximumPoint()); - return pos1.getMaximum(pos2); - } - - @Override - public void setOrigin(BlockVector3 pos) { - this.min = pos; - } - - public BlockVector3 getPos(BlockVector3 pos) { - if (min == null) { - min = pos; - } - mutable1.mutX(pos.getX() - min.getX()); - mutable1.mutY(pos.getY() - min.getY()); - mutable1.mutZ(pos.getZ() - min.getZ()); - Vector3 tmp = getTransform().apply(mutable1); - mutable2.mutX(tmp.getX() + min.getX()); - mutable2.mutY(tmp.getY() + min.getY()); - mutable2.mutZ(tmp.getZ() + min.getZ()); - return mutable2; - } - - public BlockVector3 getPos(int x, int y, int z) { - if (min == null) { - min = BlockVector3.at(x, y, z); - } - mutable1.mutX(x - min.getX()); - mutable1.mutY(y - min.getY()); - mutable1.mutZ(z - min.getZ()); - Vector3 tmp = getTransform().apply(mutable1); - mutable2.mutX(tmp.getX() + min.getX()); - mutable2.mutY(tmp.getY() + min.getY()); - mutable2.mutZ(tmp.getZ() + min.getZ()); - return tmp.toBlockPoint(); - } - - @Override - public BlockState getBlock(int x, int y, int z) { - BlockVector3 p = getPos(x, y, z); - return transform(super.getBlock(p.getX(), p.getY(), p.getZ())); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return transform(super.getFullBlock(getPos(position))); - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - BlockVector3 p = getPos(x, y, z); - return super.getBiomeType(p.getX(), y, p.getZ()); - } - - @Override - @SuppressWarnings("unchecked") - public > boolean setBlock(int x, int y, int z, T block) - throws WorldEditException { - return super.setBlock(getPos(x, y, z), transformInverse(block)); - } - - - @Override - @SuppressWarnings("unchecked") - public > boolean setBlock(BlockVector3 location, B block) - throws WorldEditException { - return super.setBlock(getPos(location), transformInverse(block)); - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - BlockVector3 p = getPos(x, y, z); - return super.setBiome(p.getX(), p.getY(), p.getZ(), 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 3f7c746c3..76f22a194 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 @@ -305,22 +305,24 @@ public class DiskOptimizedClipboard extends LinearClipboard { private void init() throws IOException { if (this.fileChannel == null) { this.fileChannel = braf.getChannel(); - try { - FileLock lock = this.fileChannel.lock(); - LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock)); - } catch (OverlappingFileLockException e) { - LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName()); - if (existing != null) { - long ms = System.currentTimeMillis() - existing.lockHeldSince; - LOGGER.error( - "Cannot lock clipboard file {} acquired by thread {}, {}ms ago", - file.getName(), - existing.thread, - ms - ); + if (Settings.settings().CLIPBOARD.LOCK_CLIPBOARD_FILE) { + try { + FileLock lock = this.fileChannel.lock(); + LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock)); + } catch (OverlappingFileLockException e) { + LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName()); + if (existing != null) { + long ms = System.currentTimeMillis() - existing.lockHeldSince; + LOGGER.error( + "Cannot lock clipboard file {} acquired by thread {}, {}ms ago", + file.getName(), + existing.thread, + ms + ); + } + // Rethrow to prevent clipboard access + throw e; } - // Rethrow to prevent clipboard access - throw e; } this.byteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, braf.length()); } 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 e57ccb490..c266fd544 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 @@ -19,12 +19,9 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.function.Supplier; @@ -80,28 +77,18 @@ public class MultiBatchProcessor implements IBatchProcessor { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - Map> ordered = new HashMap<>(); + Map> ordered = new HashMap<>(); IChunkSet chunkSet = set; for (IBatchProcessor processor : processors) { if (processor.getScope() != ProcessorScope.ADDING_BLOCKS) { - ordered.merge( - processor.getScope().intValue(), - new HashSet<>(Collections.singleton(processor)), - (existing, theNew) -> { - existing.add(processor); - return existing; - } - ); + ordered.computeIfAbsent(processor.getScope().intValue(), k -> new ArrayList<>()) + .add(processor); continue; } chunkSet = processSet(processor, chunk, get, chunkSet); } - if (ordered.size() > 0) { - for (int i = 1; i <= 4; i++) { - Set processors = ordered.get(i); - if (processors == null) { - continue; - } + if (!ordered.isEmpty()) { + for (List processors : ordered.values()) { for (IBatchProcessor processor : processors) { chunkSet = processSet(processor, chunk, get, chunkSet); if (chunkSet == null) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java index 93ab1ac99..a839ec323 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/transform/RandomTransform.java @@ -7,10 +7,10 @@ import com.fastasyncworldedit.core.util.collection.RandomCollection; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -20,10 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull; public class RandomTransform extends SelectTransform { private final SimpleRandom random; - private final Map weights = new HashMap<>(); + private final List> weights; private transient RandomCollection collection; - private transient LinkedHashSet extents = new LinkedHashSet<>(); public RandomTransform() { this(new TrueRandom()); @@ -36,27 +35,27 @@ public class RandomTransform extends SelectTransform { */ public RandomTransform(SimpleRandom random) { this.random = random; + this.weights = new ArrayList<>(); } @Override public AbstractDelegateExtent getExtent(int x, int y, int z) { - return collection.next(x, y, z); + return collection.next(this.random, x, y, z); } @Override public AbstractDelegateExtent getExtent(int x, int z) { - return collection.next(x, 0, z); + return collection.next(this.random, x, 0, z); } @Override public ResettableExtent setExtent(Extent extent) { if (collection == null) { - collection = RandomCollection.of(weights, random); - extents = new LinkedHashSet<>(weights.keySet()); + collection = RandomCollection.of(weights); } super.setExtent(extent); - for (ResettableExtent current : extents) { - current.setExtent(extent); + for (RandomCollection.Weighted current : this.weights) { + current.value().setExtent(extent); } return this; } @@ -72,13 +71,12 @@ public class RandomTransform extends SelectTransform { */ public void add(ResettableExtent extent, double chance) { checkNotNull(extent); - weights.put(extent, chance); - collection = RandomCollection.of(weights, random); - this.extents.add(extent); + weights.add(new RandomCollection.Weighted<>(extent, chance)); + collection = RandomCollection.of(weights); } public Set getExtents() { - return extents; + return this.weights.stream().map(RandomCollection.Weighted::value).collect(Collectors.toSet()); } public RandomCollection getCollection() { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java index a9c1ec962..638872ea8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/ExpressionPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; @@ -57,4 +58,9 @@ public class ExpressionPattern extends AbstractPattern { } } + @Override + public Pattern fork() { + return new ExpressionPattern(this.expression.clone()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java index 7c923c4d4..e99383d06 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear2DBlockPattern.java @@ -7,8 +7,15 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear2DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear2DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; @@ -47,4 +54,10 @@ public class Linear2DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear2DBlockPattern(forked, this.xScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java index 04028244d..e4d3822cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/Linear3DBlockPattern.java @@ -7,8 +7,15 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static java.lang.Math.floorDiv; +/** + * @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern} + * combined with {@link com.fastasyncworldedit.core.math.random.Linear3DRandom}. + */ +@Deprecated(forRemoval = true, since = "TODO") public class Linear3DBlockPattern extends AbstractPattern { private final Pattern[] patternsArray; @@ -51,4 +58,10 @@ public class Linear3DBlockPattern extends AbstractPattern { return patternsArray[index].apply(extent, get, set); } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new Linear3DBlockPattern(forked, this.xScale, this.yScale, this.zScale); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java index 086cf3a31..1490bf37d 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/LinearBlockPattern.java @@ -1,5 +1,6 @@ package com.fastasyncworldedit.core.function.pattern; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -7,6 +8,8 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + public class LinearBlockPattern extends AbstractPattern implements ResettablePattern { private final Pattern[] patternsArray; @@ -15,7 +18,7 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat /** * Create a new {@link Pattern} instance * - * @param patterns array of patterns to linearly choose from based on x/z coordinates + * @param patterns array of patterns to linearly choose from */ public LinearBlockPattern(Pattern[] patterns) { this.patternsArray = patterns; @@ -23,18 +26,14 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat @Override public BaseBlock applyBlock(BlockVector3 position) { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].applyBlock(position); + index = (index + 1) % patternsArray.length; + return patternsArray[index].applyBlock(position); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - if (index == patternsArray.length) { - index = 0; - } - return patternsArray[index++].apply(extent, get, set); + index = (index + 1) % patternsArray.length; + return patternsArray[index].apply(extent, get, set); } @Override @@ -42,4 +41,10 @@ public class LinearBlockPattern extends AbstractPattern implements ResettablePat index = 0; } + @Override + public Pattern fork() { + final Pattern[] forked = Arrays.stream(this.patternsArray).map(Pattern::fork).toArray(Pattern[]::new); + return new LinearBlockPattern(forked); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java index 5d840d771..a5210feba 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/MaskedPattern.java @@ -43,4 +43,9 @@ public class MaskedPattern extends AbstractPattern { return secondary.apply(extent, get, set); } + @Override + public Pattern fork() { + return new MaskedPattern(this.mask.copy(), this.primary.fork(), this.secondary.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java index d9fefb1bc..b4e9aac37 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoXPattern.java @@ -36,4 +36,9 @@ public class NoXPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoXPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java index 05d26f496..2fefaedfc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoYPattern.java @@ -36,4 +36,9 @@ public class NoYPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoYPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java index faebb59aa..8c100c5e3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/NoZPattern.java @@ -1,6 +1,7 @@ package com.fastasyncworldedit.core.function.pattern; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.AbstractPattern; @@ -36,4 +37,9 @@ public class NoZPattern extends AbstractPattern { return pattern.apply(extent, mutable, set); } + @Override + public Pattern fork() { + return new NoZPattern(this.pattern.fork()); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java index 894f9d06a..628b848e8 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/OffsetPattern.java @@ -60,4 +60,9 @@ public class OffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public Pattern fork() { + return new OffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java index 3eb5c3b77..c0afd02e3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomOffsetPattern.java @@ -72,4 +72,9 @@ public class RandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, mutable); } + @Override + public Pattern fork() { + return new RandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java index cda875f04..541aaa494 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RelativePattern.java @@ -63,4 +63,11 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter origin = null; } + @Override + public Pattern fork() { + RelativePattern forked = new RelativePattern(this.pattern.fork(), this.minY, this.maxY); + forked.origin = this.origin; // maintain origin for forks + return forked; + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java index 12b64a497..54ecf6676 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SolidRandomOffsetPattern.java @@ -94,4 +94,9 @@ public class SolidRandomOffsetPattern extends AbstractPattern { return pattern.apply(extent, get, set); } + @Override + public Pattern fork() { + return new SolidRandomOffsetPattern(this.pattern.fork(), this.dx, this.dy, this.dz, this.minY, this.maxY); + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java index 73327f94a..34866fc54 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/SurfaceRandomOffsetPattern.java @@ -129,4 +129,9 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern { return !block.getBlockType().getMaterial().isMovementBlocker(); } + @Override + public Pattern fork() { + return new SurfaceRandomOffsetPattern(this.pattern.fork(), this.moves, this.minY, this.maxY); + } + } 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 7d0bfe76e..eb2e3da59 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 @@ -15,8 +15,10 @@ import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; +import org.apache.logging.log4j.Logger; import java.io.File; import java.io.FileInputStream; @@ -35,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DiskStorageHistory extends FaweStreamChangeSet { + private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Map> NEXT_INDEX = new ConcurrentHashMap<>(); private UUID uuid; @@ -141,9 +144,9 @@ public class DiskStorageHistory extends FaweStreamChangeSet { e.printStackTrace(); return; } - EditSession session = toEditSession(actor, regions); - session.setBlocks(this, ChangeSetExecutor.Type.UNDO); - deleteFiles(); + try (EditSession session = toEditSession(actor, regions)) { + session.setBlocks(this, ChangeSetExecutor.Type.UNDO); + } } public void undo(Actor actor) { @@ -371,9 +374,14 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!bdFile.exists()) { return null; } - FaweInputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile)); - readHeader(is); - return is; + try { + FaweInputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile)); + readHeader(is); + return is; + } catch (IOException e) { + LOGGER.error("Could not load block history file {}", bdFile); + throw e; + } } @Override @@ -381,7 +389,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!bioFile.exists()) { return null; } - return MainUtil.getCompressedIS(new FileInputStream(bioFile)); + try { + return MainUtil.getCompressedIS(new FileInputStream(bioFile)); + } catch (IOException e) { + LOGGER.error("Could not load biome history file {}", bdFile); + throw e; + } } @Override @@ -389,7 +402,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!enttFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(enttFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(enttFile))); + } catch (IOException e) { + LOGGER.error("Could not load entity create history file {}", bdFile); + throw e; + } } @Override @@ -397,7 +415,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!entfFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(entfFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(entfFile))); + } catch (IOException e) { + LOGGER.error("Could not load entity remove history file {}", bdFile); + throw e; + } } @Override @@ -405,7 +428,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!nbttFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbttFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbttFile))); + } catch (IOException e) { + LOGGER.error("Could not load tile create history file {}", bdFile); + throw e; + } } @Override @@ -413,7 +441,12 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (!nbtfFile.exists()) { return null; } - return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile))); + try { + return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile))); + } catch (IOException e) { + LOGGER.error("Could not load tile remove history file {}", bdFile); + throw e; + } } @Override 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 6e7e4068b..1f01f99de 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 @@ -7,6 +7,7 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; import org.apache.logging.log4j.Logger; import java.io.IOException; @@ -125,6 +126,26 @@ public class RollbackOptimizedHistory extends DiskStorageHistory { } } + @Override + public void addBiomeChange(int x, int y, int z, BiomeType from, BiomeType to) { + super.addBiomeChange(x, y, z, from, to); + if (x < minX) { + minX = x; + } else if (x > maxX) { + maxX = x; + } + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + if (z < minZ) { + minZ = z; + } else if (z > maxZ) { + maxZ = z; + } + } + @Override public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { minX = x; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/BlockPositionChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/BlockPositionChange.java new file mode 100644 index 000000000..e9c233269 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/BlockPositionChange.java @@ -0,0 +1,16 @@ +package com.fastasyncworldedit.core.history.change; + +import com.sk89q.worldedit.history.change.Change; +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents a change that is associated with {@code (x, y, z)} block coordinates. + * @since TODO + */ +@ApiStatus.Internal +public sealed abstract class BlockPositionChange implements Change + permits MutableBlockChange, MutableFullBlockChange { + public int x; + public int y; + public int z; +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableBlockChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableBlockChange.java index f4797581f..473940507 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableBlockChange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableBlockChange.java @@ -2,17 +2,13 @@ package com.fastasyncworldedit.core.history.change; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.history.UndoContext; -import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.block.BlockState; +import org.jetbrains.annotations.ApiStatus; -public class MutableBlockChange implements Change { - - public int z; - public int y; - public int x; +@ApiStatus.Internal +public final class MutableBlockChange extends BlockPositionChange { public int ordinal; - public MutableBlockChange(int x, int y, int z, int ordinal) { this.x = x; this.y = y; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableFullBlockChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableFullBlockChange.java index 2b99cb8a9..b23903f45 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableFullBlockChange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableFullBlockChange.java @@ -4,15 +4,12 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBagException; import com.sk89q.worldedit.history.UndoContext; -import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypesCache; +import org.jetbrains.annotations.ApiStatus; -public class MutableFullBlockChange implements Change { - - public int z; - public int y; - public int x; +@ApiStatus.Internal +public final class MutableFullBlockChange extends BlockPositionChange { public int from; public int to; public BlockBag blockBag; 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 c6a2d9bb0..4bbe1a109 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 @@ -257,12 +257,14 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public EditSession toEditSession(Actor actor, Region[] regions) { - EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(getWorld()).actor(actor). - fastMode(false).checkMemory(false).changeSet(this).limitUnlimited(); - if (regions != null) { - builder.allowedRegions(regions); - } else { - builder.allowedRegionsEverywhere(); + EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world) + .checkMemory(false) + .changeSetNull() + .fastMode(false) + .limitUnprocessed(actor) + .actor(actor); + if (!actor.getLimit().RESTRICT_HISTORY_TO_REGIONS) { + builder = builder.allowedRegionsEverywhere(); } EditSession editSession = builder.build(); editSession.setSize(1); 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 c2ae362ae..f20af641b 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 @@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.history.change.MutableBlockChange; import com.fastasyncworldedit.core.history.change.MutableEntityChange; import com.fastasyncworldedit.core.history.change.MutableFullBlockChange; import com.fastasyncworldedit.core.history.change.MutableTileChange; +import com.fastasyncworldedit.core.history.change.BlockPositionChange; import com.fastasyncworldedit.core.internal.exception.FaweSmallEditUnsupportedException; import com.fastasyncworldedit.core.internal.io.FaweInputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; @@ -20,6 +21,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockTypes; +import org.jetbrains.annotations.ApiStatus; import java.io.EOFException; import java.io.IOException; @@ -32,6 +34,7 @@ import java.util.NoSuchElementException; /** * FAWE stream ChangeSet offering support for extended-height worlds */ +@ApiStatus.Internal public abstract class FaweStreamChangeSet extends AbstractChangeSet { public static final int HEADER_SIZE = 9; @@ -68,19 +71,15 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } } - public interface FaweStreamPositionDelegate { + interface FaweStreamPositionDelegate { void write(OutputStream out, int x, int y, int z) throws IOException; - int readX(FaweInputStream in) throws IOException; - - int readY(FaweInputStream in) throws IOException; - - int readZ(FaweInputStream in) throws IOException; + void read(FaweInputStream in, BlockPositionChange change) throws IOException; } - public interface FaweStreamIdDelegate { + interface FaweStreamIdDelegate { void writeChange(FaweOutputStream out, int from, int to) throws IOException; @@ -138,6 +137,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } if (mode == 1 || mode == 4) { // small posDel = new FaweStreamPositionDelegate() { + final byte[] buffer = new byte[4]; int lx; int ly; int lz; @@ -162,23 +162,14 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { out.write(b4); } - final byte[] buffer = new byte[4]; - @Override - public int readX(FaweInputStream in) throws IOException { + public void read(final FaweInputStream in, final BlockPositionChange change) throws IOException { in.readFully(buffer); - return lx = lx + ((((buffer[1] & 0xFF) + ((MathMan.unpair16x(buffer[3])) << 8)) << 20) >> 20); + change.x = lx = lx + ((((buffer[1] & 0xFF) | ((MathMan.unpair16x(buffer[3])) << 8)) << 20) >> 20); + change.y = (ly = ly + buffer[0]) & 0xFF; + change.z = lz = lz + ((((buffer[2] & 0xFF) | ((MathMan.unpair16y(buffer[3])) << 8)) << 20) >> 20); } - @Override - public int readY(FaweInputStream in) { - return (ly = ly + buffer[0]) & 0xFF; - } - - @Override - public int readZ(FaweInputStream in) throws IOException { - return lz = lz + ((((buffer[2] & 0xFF) + ((MathMan.unpair16y(buffer[3])) << 8)) << 20) >> 20); - } }; } else { posDel = new FaweStreamPositionDelegate() { @@ -201,19 +192,11 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } @Override - public int readX(FaweInputStream is) throws IOException { - is.readFully(buffer); - return lx = (lx + (buffer[0] & 0xFF) + (buffer[1] << 8)); - } - - @Override - public int readY(FaweInputStream is) throws IOException { - return ly = (ly + (buffer[4] & 0xFF) + (buffer[5] << 8)); - } - - @Override - public int readZ(FaweInputStream is) throws IOException { - return lz = (lz + (buffer[2] & 0xFF) + (buffer[3] << 8)); + public void read(final FaweInputStream in, final BlockPositionChange change) throws IOException { + in.readFully(buffer); + change.x = lx = lx + ((buffer[0] & 0xFF) | (buffer[1] << 8)); + change.z = lz = lz + ((buffer[2] & 0xFF) | (buffer[3]) << 8); + change.y = ly = ly + ((buffer[4] & 0xFF) | (buffer[5]) << 8); } }; } @@ -353,7 +336,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { os.write((byte) (z)); // only need to store biomes in the 4x4x4 chunks so only need one byte for y still (signed byte -128 -> 127) // means -512 -> 508. Add 128 to avoid negative value casting. - os.write((byte) (y + 128)); + os.write((byte) (y + 32)); os.writeVarInt(from.getInternalId()); os.writeVarInt(to.getInternalId()); } catch (IOException e) { @@ -428,9 +411,9 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public MutableBlockChange read() { try { - change.x = posDel.readX(is) + originX; - change.y = posDel.readY(is); - change.z = posDel.readZ(is) + originZ; + posDel.read(is, change); + change.x += originX; + change.z += originZ; idDel.readCombined(is, change, dir); return change; } catch (EOFException ignored) { @@ -545,9 +528,9 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public MutableFullBlockChange read() { try { - change.x = posDel.readX(is) + originX; - change.y = posDel.readY(is); - change.z = posDel.readZ(is) + originZ; + posDel.read(is, change); + change.x += originX; + change.z += originZ; idDel.readCombined(is, change); return change; } catch (EOFException ignored) { @@ -765,11 +748,9 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { 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; - int y = posDel.readY(fis); - int z = posDel.readZ(fis) + ox; + posDel.read(fis, change); idDel.readCombined(fis, change); - summary.add(x, z, change.to); + summary.add(change.x + ox, change.z + oz, change.to); } } } catch (EOFException ignored) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java new file mode 100644 index 000000000..4f039031e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear2DRandom.java @@ -0,0 +1,50 @@ +package com.fastasyncworldedit.core.math.random; + +import static com.fastasyncworldedit.core.math.random.Linear3DRandom.doubleDiv; +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear2DRandom implements SimpleRandom { + private final int xScale; + private final int zScale; + + /** + * Creates a new {@link Linear2DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear2DRandom(final int xScale, final int zScale) { + this.xScale = xScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java new file mode 100644 index 000000000..87f350fe4 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/Linear3DRandom.java @@ -0,0 +1,58 @@ +package com.fastasyncworldedit.core.math.random; + +import static java.lang.Math.floorDiv; + +/** + * A {@link SimpleRandom} that deterministically maps coordinates + * to values. + * @since TODO + */ +public class Linear3DRandom implements SimpleRandom { + + private final int xScale; + private final int yScale; + private final int zScale; + + /** + * Creates a new {@link Linear3DRandom} instance + * + * @param xScale the scale applied to the x component of a coordinate + * @param yScale the scale applied to the y component of a coordinate + * @param zScale the scale applied to the z component of a coordinate + */ + public Linear3DRandom(final int xScale, final int yScale, final int zScale) { + this.xScale = xScale; + this.yScale = yScale; + this.zScale = zScale; + } + + @Override + public double nextDouble(final int x, final int y, final int z) { + return nextDouble(x, y, z, 1d); + } + + @Override + public double nextDouble(final int x, final int y, final int z, double bound) { + double index = (doubleDiv(x, this.xScale) + doubleDiv(y, this.yScale) + doubleDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + + // used to avoid explicit conversion at call site + static double doubleDiv(double dividend, double divisor) { + // add a minimal value to avoid too many integral values hitting the exact weight of an entry in SimpleRandomCollection + return Math.nextUp(dividend) / divisor; + } + + @Override + public int nextInt(final int x, final int y, final int z, final int bound) { + int index = (floorDiv(x, this.xScale) + floorDiv(y, this.yScale) + floorDiv(z, this.zScale)) % bound; + if (index < 0) { + index += bound; + } + return index; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java index e38214936..8b22b66a2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/random/SimpleRandom.java @@ -13,6 +13,20 @@ public interface SimpleRandom { */ double nextDouble(int x, int y, int z); + /** + * Generate a random double from three integer components. + * The generated value is between 0 (inclusive) and {@code bound} (exclusive). + * + * @param x the first component + * @param y the second component + * @param z the third component + * @param bound upper bound (exclusive) + * @return a double between 0 (inclusive) and {@code bound} (exclusive) + */ + default double nextDouble(int x, int y, int z, double bound) { + return nextDouble(x, y, z) * bound; + } + /** * Generate a random integer from three integer components. * The generated value is between 0 (inclusive) and 1 (exclusive) @@ -24,8 +38,8 @@ public interface SimpleRandom { * @return a random integer between 0 (inclusive) and {@code bound} (exclusive) */ default int nextInt(int x, int y, int z, int bound) { - double val = nextDouble(x, y, z); - return (int) (val * bound); + double val = nextDouble(x, y, z, bound); + return (int) val; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java index 19fa1293a..366faa8c5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java @@ -2,7 +2,6 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; @@ -18,8 +17,8 @@ public interface Filter { * @param chunkZ the z coordinate in the chunk */ default boolean appliesChunk( - @Range(from = 0, to = 15) int chunkX, - @Range(from = 0, to = 15) int chunkZ + int chunkX, + int chunkZ ) { return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 5eeafe28e..778f85ce4 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -155,7 +155,9 @@ public interface IBatchProcessor { * Utility method to trim entity and blocks with a provided contains function. * * @return false if chunk is empty of NBT + * @deprecated tiles are stored in chunk-normalised coordinate space and thus cannot use the same function as entities */ + @Deprecated(forRemoval = true, since = "2.8.4") default boolean trimNBT(IChunkSet set, Function contains) { Set ents = set.getEntities(); if (!ents.isEmpty()) { @@ -169,6 +171,26 @@ public interface IBatchProcessor { return !tiles.isEmpty() || !ents.isEmpty(); } + /** + * Utility method to trim entity and blocks with a provided contains function. + * + * @return false if chunk is empty of NBT + * @since 2.8.4 + */ + default boolean trimNBT( + IChunkSet set, Function containsEntity, Function containsTile + ) { + Set ents = set.getEntities(); + if (!ents.isEmpty()) { + ents.removeIf(ent -> !containsEntity.apply(ent.getEntityPosition().toBlockPoint())); + } + Map tiles = set.getTiles(); + if (!tiles.isEmpty()) { + tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !containsTile.apply(blockVector3CompoundTagEntry.getKey())); + } + return !tiles.isEmpty() || !ents.isEmpty(); + } + /** * Join two processors and return the result. */ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java index 84f98e6d7..2586ea24c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunk.java @@ -1,8 +1,8 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; @@ -34,6 +34,16 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet { */ int getZ(); + /** + * Return the minimum block coordinate of the chunk + * + * @return BlockVector3 of minimum block coordinate + * @since 2.8.4 + */ + default BlockVector3 getChunkBlockCoord() { + return BlockVector3.at(getX() << 4, getMinY(), getZ() << 4); + } + /** * If the chunk is a delegate, returns its parent's root * diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java index ce2761390..8a704e9cb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkCache.java @@ -1,14 +1,12 @@ package com.fastasyncworldedit.core.queue; -import org.jetbrains.annotations.Range; - /** * IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple * IQueueExtents - avoids conversion between a palette and raw data on every block get */ public interface IChunkCache extends Trimable { - T get(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + T get(int chunkX, int chunkZ); @Override default boolean trim(boolean aggressive) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java index e0b37f75c..0c3198382 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java @@ -7,7 +7,6 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import org.jetbrains.annotations.Range; import javax.annotation.Nullable; import java.io.Flushable; @@ -51,12 +50,12 @@ public interface IQueueExtent extends Flushable, Trimable, ICh * Get the cached get object. This is faster than getting the object using NMS and allows for * wrapping. */ - IChunkGet getCachedGet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + IChunkGet getCachedGet(int chunkX, int chunkZ); /** * Get the cached chunk set object. */ - IChunkSet getCachedSet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ); + IChunkSet getCachedSet(int chunkX, int chunkZ); /** * Submit the chunk so that it's changes are applied to the world 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 2d2b45aae..3d16024de 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 @@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -42,9 +43,10 @@ import java.util.Set; import java.util.concurrent.ForkJoinTask; import java.util.stream.IntStream; -public class ParallelQueueExtent extends PassthroughExtent { +public final class ParallelQueueExtent extends PassthroughExtent { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final ThreadLocal extents = new ThreadLocal<>(); private final World world; private final QueueHandler handler; @@ -73,10 +75,36 @@ public class ParallelQueueExtent extends PassthroughExtent { this.fastmode = fastmode; } + /** + * Removes the extent currently associated with the calling thread. + */ + public static void clearCurrentExtent() { + extents.remove(); + } + + /** + * Sets the extent associated with the calling thread. + */ + public static void setCurrentExtent(Extent extent) { + extents.set(extent); + } + + private void enter(Extent extent) { + setCurrentExtent(extent); + } + + private void exit() { + clearCurrentExtent(); + } + @Override @SuppressWarnings({"unchecked", "rawtypes"}) public IQueueExtent getExtent() { - return (IQueueExtent) super.getExtent(); + Extent extent = extents.get(); + if (extent == null) { + extent = super.getExtent(); + } + return (IQueueExtent) extent; } @Override @@ -103,9 +131,12 @@ public class ParallelQueueExtent extends PassthroughExtent { // Get a pool, to operate on the chunks in parallel 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); + if (size <= 1) { + // if PQE is ever used with PARALLEL_THREADS = 1, or only one chunk is edited, just run sequentially + while (chunksIter.hasNext()) { + BlockVector2 pos = chunksIter.next(); + getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); + } } else { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { try { @@ -114,6 +145,7 @@ public class ParallelQueueExtent extends PassthroughExtent { final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue(); queue.setFastMode(fastmode); queue.setFaweExceptionArray(faweExceptionReasonsUsed); + enter(queue); synchronized (queue) { try { ChunkFilterBlock block = null; @@ -154,6 +186,8 @@ public class ParallelQueueExtent extends PassthroughExtent { exceptionCount++; LOGGER.warn(message); } + } finally { + exit(); } })).toArray(ForkJoinTask[]::new); // Join filters 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 aeb84f206..98d4832fa 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 @@ -69,7 +69,8 @@ public abstract class QueueHandler implements Trimable, Runnable { * Main "work-horse" queue for FAWE. Handles chunk submission (and chunk submission alone). Blocking in order to forcibly * prevent overworking/over-submission of chunk process tasks. */ - private final ThreadPoolExecutor blockingExecutor = FaweCache.INSTANCE.newBlockingExecutor(); + private final ThreadPoolExecutor blockingExecutor = FaweCache.INSTANCE.newBlockingExecutor( + "FAWE QueueHandler Blocking Executor - %d"); /** * Queue for tasks to be completed on the main thread. These take priority of tasks submitted to syncWhenFree queue */ @@ -428,7 +429,7 @@ public abstract class QueueHandler implements Trimable, Runnable { * Sets the current thread's {@link IQueueExtent} instance in the queue pool to null. */ public void unCache() { - queuePool.set(null); + queuePool.remove(); } private IQueueExtent pool() { 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 634778fef..2cb6c5b98 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 @@ -9,7 +9,6 @@ import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.internal.exception.FaweException; -import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; @@ -46,15 +45,13 @@ import java.util.concurrent.locks.ReentrantLock; * This queue is reusable {@link #init(Extent, IChunkCache, IChunkCache)} */ @SuppressWarnings({"unchecked", "rawtypes"}) -public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implements IQueueExtent { +public final class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implements IQueueExtent { private static final Logger LOGGER = LogManagerCompat.getLogger(); - // Pool discarded chunks for reuse (can safely be cleared by another thread) - // private static final ConcurrentLinkedQueue CHUNK_POOL = new ConcurrentLinkedQueue<>(); // Chunks currently being queued / worked on - private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); - private final ConcurrentLinkedQueue submissions = new ConcurrentLinkedQueue<>(); + private final Long2ObjectLinkedOpenHashMap> chunks = new Long2ObjectLinkedOpenHashMap<>(); + private final ConcurrentLinkedQueue> submissions = new ConcurrentLinkedQueue<>(); private final ReentrantLock getChunkLock = new ReentrantLock(); private World world = null; private int minY = 0; @@ -145,12 +142,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen if (!this.initialized) { return; } - if (!this.chunks.isEmpty()) { - getChunkLock.lock(); - for (IChunk chunk : this.chunks.values()) { - chunk.recycle(); - } + getChunkLock.lock(); + try { this.chunks.clear(); + } finally { getChunkLock.unlock(); } this.enabledQueue = true; @@ -161,6 +156,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen this.setProcessor(EmptyBatchProcessor.getInstance()); this.setPostProcessor(EmptyBatchProcessor.getInstance()); this.world = null; + this.faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; } /** @@ -244,7 +240,6 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen } } if (chunk.isEmpty()) { - chunk.recycle(); Future result = Futures.immediateFuture(null); return (V) result; } 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 e4a18ef69..a7417eddf 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 @@ -1,7 +1,5 @@ package com.fastasyncworldedit.core.queue.implementation.chunk; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; @@ -11,35 +9,34 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.fastasyncworldedit.core.queue.Pool; +import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; +import com.fastasyncworldedit.core.util.MemUtil; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; 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 org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; /** * An abstract {@link IChunk} class that implements basic get/set blocks. */ @SuppressWarnings("rawtypes") public class ChunkHolder> implements IQueueChunk { - - private static final Pool POOL = FaweCache.INSTANCE.registerPool( - ChunkHolder.class, - ChunkHolder::new, - Settings.settings().QUEUE.POOL - ); + private static final Logger LOGGER = LogManagerCompat.getLogger(); public static ChunkHolder newInstance() { - return POOL.poll(); + return new ChunkHolder(); } private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes) @@ -62,16 +59,12 @@ public class ChunkHolder> implements IQueueChunk { this.delegate = delegate; } + private static final AtomicBoolean recycleWarning = new AtomicBoolean(false); @Override - public synchronized void recycle() { - delegate = NULL; - if (chunkSet != null) { - chunkSet.recycle(); - chunkSet = null; + public void recycle() { + if (!recycleWarning.getAndSet(true)) { + LOGGER.warn("ChunkHolder should not be recycled.", new Exception()); } - chunkExisting = null; - extent = null; - POOL.offer(this); } public long initAge() { @@ -959,7 +952,7 @@ public class ChunkHolder> implements IQueueChunk { public final IChunkGet getOrCreateGet() { if (chunkExisting == null) { chunkExisting = newWrappedGet(); - chunkExisting.trim(false); + chunkExisting.trim(MemUtil.isMemoryLimited()); } return chunkExisting; } @@ -1017,7 +1010,6 @@ public class ChunkHolder> implements IQueueChunk { // Do nothing }); } - recycle(); return null; } @@ -1030,11 +1022,12 @@ public class ChunkHolder> implements IQueueChunk { IChunkGet get = getOrCreateGet(); try { get.lockCall(); + trackExtent(); boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); + final int copyKey = get.setCreateCopy(postProcess); final IChunkSet iChunkSet = getExtent().processSet(this, get, set); Runnable finalizer; if (postProcess) { - int copyKey = get.setCreateCopy(true); finalizer = () -> { getExtent().postProcess(this, get.getCopy(copyKey), iChunkSet); finalize.run(); @@ -1045,11 +1038,24 @@ public class ChunkHolder> implements IQueueChunk { return get.call(set, finalizer); } finally { get.unlockCall(); + untrackExtent(); } } return null; } + // "call" can be called by QueueHandler#blockingExecutor. In such case, we still want the other thread + // to use this SingleThreadQueueExtent. Otherwise, many threads might end up locking on **one** STQE. + // This way, locking is spread across multiple STQEs, allowing for better performance + + private void trackExtent() { + ParallelQueueExtent.setCurrentExtent(extent); + } + + private void untrackExtent() { + ParallelQueueExtent.clearCurrentExtent(); + } + /** * Get the extent this chunk is in. */ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java index e7038deaa..6ae147765 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java @@ -51,11 +51,10 @@ public class ExtentTraverser { return last; } - @SuppressWarnings("unchecked") @Nullable - public U findAndGet(Class clazz) { - ExtentTraverser traverser = find(clazz); - return (traverser != null) ? (U) traverser.get() : null; + public U findAndGet(Class clazz) { + ExtentTraverser traverser = find(clazz); + return (traverser != null) ? traverser.get() : null; } @SuppressWarnings("unchecked") 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 8122a840c..41c4e5704 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 @@ -38,6 +38,9 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; @@ -56,6 +59,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; @@ -70,6 +76,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -91,6 +98,10 @@ import static java.lang.System.arraycopy; public class MainUtil { private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final String CURL_USER_AGENT = "curl/8.1.1"; + private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); public static List filter(String prefix, List suggestions) { if (prefix.isEmpty()) { @@ -519,12 +530,53 @@ public class MainUtil { return destFile; } - public static BufferedImage readImage(InputStream in) throws IOException { - return MainUtil.toRGB(ImageIO.read(in)); + public static BufferedImage readImage(InputStream stream) throws IOException { + final ImageInputStream imageStream = ImageIO.createImageInputStream(stream); + if (imageStream == null) { + throw new IOException("Can't find suitable ImageInputStream"); + } + Iterator iter = ImageIO.getImageReaders(imageStream); + if (!iter.hasNext()) { + throw new IOException("Could not get image reader from stream."); + } + ImageReader reader = iter.next(); + ImageReadParam param = reader.getDefaultReadParam(); + reader.setInput(imageStream, true, true); + BufferedImage bi; + try { + bi = reader.read(0, param); + } finally { + reader.dispose(); + stream.close(); + imageStream.close(); + } + return MainUtil.toRGB(bi); } public static BufferedImage readImage(URL url) throws IOException { - return readImage(url.openStream()); + try { + final URI uri = url.toURI(); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + + if (uri.getHost().equalsIgnoreCase("i.imgur.com")) { + requestBuilder = requestBuilder.setHeader("User-Agent", CURL_USER_AGENT); + } + + final HttpResponse response = HTTP_CLIENT.send( + requestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream() + ); + try (final InputStream body = response.body()) { + if (response.statusCode() > 299) { + throw new IOException("Expected 2xx as response code, but received " + response.statusCode()); + } + return readImage(body); + } + } catch (InterruptedException e) { + throw new IOException("request was interrupted", e); + } catch (URISyntaxException e) { + throw new IOException("failed to parse url to uri reference", e); + } } public static BufferedImage readImage(File file) throws IOException { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/FastRandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/FastRandomCollection.java index 61afe2dcd..e332ad231 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/FastRandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/FastRandomCollection.java @@ -4,15 +4,14 @@ import com.fastasyncworldedit.core.math.random.SimpleRandom; import com.fastasyncworldedit.core.util.MathMan; import java.util.ArrayList; -import java.util.Map; +import java.util.List; import java.util.Optional; -public class FastRandomCollection extends RandomCollection { +public final class FastRandomCollection implements RandomCollection { private final T[] values; - private FastRandomCollection(T[] values, SimpleRandom random) { - super(random); + private FastRandomCollection(T[] values) { this.values = values; } @@ -22,16 +21,15 @@ public class FastRandomCollection extends RandomCollection { * {@code Optional} in any case. * * @param weights the weight of the values. - * @param random the random generator to use for this collection. * @param the value type. * @return an {@link Optional} containing the new collection if it could be created, {@link * Optional#empty()} otherwise. * @see RandomCollection for API usage. */ - public static Optional> create(Map weights, SimpleRandom random) { + public static Optional> create(List> weights) { int max = 0; int[] counts = new int[weights.size()]; - Double[] weightDoubles = weights.values().toArray(new Double[0]); + double[] weightDoubles = weights.stream().mapToDouble(Weighted::weight).toArray(); for (int i = 0; i < weightDoubles.length; i++) { int weight = (int) (weightDoubles[i] * 100); counts[i] = weight; @@ -47,21 +45,21 @@ public class FastRandomCollection extends RandomCollection { return Optional.empty(); } ArrayList parsed = new ArrayList<>(); - for (Map.Entry entry : weights.entrySet()) { - int num = (int) (100 * entry.getValue()); + for (Weighted entry : weights) { + int num = (int) (100 * entry.weight()); for (int j = 0; j < num / gcd; j++) { - parsed.add(entry.getKey()); + parsed.add(entry.value()); } } @SuppressWarnings("unchecked") T[] values = (T[]) parsed.toArray(); - FastRandomCollection fastRandomCollection = new FastRandomCollection<>(values, random); + FastRandomCollection fastRandomCollection = new FastRandomCollection<>(values); return Optional.of(fastRandomCollection); } @Override - public T next(int x, int y, int z) { - return values[getRandom().nextInt(x, y, z, values.length)]; + public T next(final SimpleRandom random, int x, int y, int z) { + return values[random.nextInt(x, y, z, values.length)]; } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java index a157ebd7c..098818558 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/RandomCollection.java @@ -2,49 +2,35 @@ package com.fastasyncworldedit.core.util.collection; import com.fastasyncworldedit.core.math.random.SimpleRandom; -import java.util.Map; +import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; /** * A RandomCollection holds multiple values that can be accessed by using - * {@link RandomCollection#next(int, int, int)}. The returned value is + * {@link RandomCollection#next(SimpleRandom, int, int, int)}. The returned value is * determined by a given {@link SimpleRandom} implementation. * * @param the type of values the collection holds. */ -public abstract class RandomCollection { - - private SimpleRandom random; - - protected RandomCollection(SimpleRandom random) { - this.random = random; - } +public sealed interface RandomCollection permits FastRandomCollection, SimpleRandomCollection { /** * Return a new RandomCollection. The implementation may differ depending on the * given arguments but there is no need to differ. * * @param weights the weighted map. - * @param random the random number generator. * @param the type the collection holds. * @return a RandomCollection using the given weights and the RNG. */ - public static RandomCollection of(Map weights, SimpleRandom random) { - checkNotNull(random); - return FastRandomCollection.create(weights, random) - .orElse(new SimpleRandomCollection<>(weights, random)); + static RandomCollection of(List> weights) { + return FastRandomCollection.create(weights) + .orElseGet(() -> new SimpleRandomCollection<>(weights)); } - public void setRandom(SimpleRandom random) { - checkNotNull(random); - this.random = random; + T next(SimpleRandom random, int x, int y, int z); + + record Weighted(T value, double weight) { + } - - public SimpleRandom getRandom() { - return random; - } - - public abstract T next(int x, int y, int z); - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java index dc2107559..8457a88be 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/SimpleRandomCollection.java @@ -2,41 +2,39 @@ package com.fastasyncworldedit.core.util.collection; import com.fastasyncworldedit.core.math.random.SimpleRandom; -import java.util.Map; +import java.util.List; import java.util.NavigableMap; import java.util.TreeMap; -public class SimpleRandomCollection extends RandomCollection { +public final class SimpleRandomCollection implements RandomCollection { - private final NavigableMap map = new TreeMap<>(); - private double total = 0; + private final NavigableMap map; + private final double total; /** * Create a {@link RandomCollection} from a weighted map and a RNG. - * It is recommended to use {@link RandomCollection#of(Map, SimpleRandom)} + * It is recommended to use {@link RandomCollection#of(List)} * instead of this constructor. * * @param weights the weighted map. - * @param random the random number generator. */ - public SimpleRandomCollection(Map weights, SimpleRandom random) { - super(random); - for (Map.Entry entry : weights.entrySet()) { - add(entry.getValue(), entry.getKey()); + public SimpleRandomCollection(List> weights) { + this.map = new TreeMap<>(); + double total = 0; + for (Weighted entry : weights) { + final double weight = entry.weight(); + if (weight <= 0) { + throw new IllegalArgumentException("Weights must be positive"); + } + total += weight; + this.map.put(total, entry.value()); } - } - - public void add(double weight, E result) { - if (weight <= 0) { - return; - } - total += weight; - map.put(total, result); + this.total = total; } @Override - public E next(int x, int y, int z) { - return map.ceilingEntry(getRandom().nextDouble(x, y, z) * this.total).getValue(); + public T next(final SimpleRandom random, int x, int y, int z) { + return map.ceilingEntry(random.nextDouble(x, y, z, this.total)).getValue(); } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java new file mode 100644 index 000000000..fe684fb8c --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/ItemTypeAdapter.java @@ -0,0 +1,26 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; + +import java.lang.reflect.Type; + +public final class ItemTypeAdapter implements JsonDeserializer { + + @Override + public ItemType deserialize(JsonElement json, Type type, JsonDeserializationContext cont) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + String id = jsonObject.get("id").getAsString(); + ItemType itemType = ItemTypes.get(id); + if (itemType == null) { + throw new JsonParseException("Could not parse item type `" + id + "`"); + } + return itemType; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java new file mode 100644 index 000000000..d817185ee --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/RegionSelectorAdapter.java @@ -0,0 +1,33 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.RegionSelectorType; + +import java.lang.reflect.Type; + +public class RegionSelectorAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public RegionSelector deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { + RegionSelectorType regionType = RegionSelectorType.valueOf(json.getAsString()); + return regionType.createSelector(); + } + + @Override + public JsonElement serialize(RegionSelector selector, Type type, JsonSerializationContext context) { + RegionSelectorType regionType = RegionSelectorType.getForSelector(selector); + // Cannot nicely deserialize Fuzzy region type + if (regionType == null || regionType == RegionSelectorType.FUZZY) { + return null; + } + return new JsonPrimitive(regionType.toString()); + } + +} 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 67bbff7af..5a5fa654e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -32,6 +32,7 @@ import com.fastasyncworldedit.core.internal.io.FaweOutputStream; import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.util.BrushCache; 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.TextureHolder; @@ -53,6 +54,7 @@ import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.NullExtent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; @@ -123,7 +125,9 @@ public class LocalSession implements TextureHolder { private transient int cuiVersion = CUI_VERSION_UNINITIALIZED; // Session related - private transient RegionSelector selector = new CuboidRegionSelector(); + //FAWE start - allow saving to session store + private RegionSelector selector = new CuboidRegionSelector(); + //FAWE end private transient boolean placeAtPos1 = false; //FAWE start private final transient List history = Collections.synchronizedList(new LinkedList<>() { @@ -594,6 +598,9 @@ public class LocalSession implements TextureHolder { long size = MainUtil.getSize(item); historySize -= size; } + // free the mask from any remaining references to e.g. extents + // if used again + new MaskTraverser(mask).reset(NullExtent.INSTANCE); } finally { historyWriteLock.unlock(); } @@ -766,6 +773,7 @@ public class LocalSession implements TextureHolder { checkNotNull(selector); selector.setWorld(world); this.selector = selector; + setDirty(); if (hasWorldOverride() && !world.equals(getWorldOverride())) { setWorldOverride(null); } 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 8ccd4f44e..177366651 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 @@ -47,6 +47,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Preload; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -70,6 +71,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.NullRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionIntersection; @@ -453,7 +455,9 @@ public class ClipboardCommands { @Switch(name = 'e', desc = "Paste entities if available") boolean pasteEntities, @Switch(name = 'b', desc = "Paste biomes if available") - boolean pasteBiomes + boolean pasteBiomes, + @Switch(name = 'x', desc = "Remove existing entities in the affected region") + boolean removeEntities ) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); final Clipboard clipboard = holder.getClipboard(); @@ -466,17 +470,22 @@ public class ClipboardCommands { } Region region = clipboard.getRegion().clone(); - if (selectPasted || onlySelect) { + if (selectPasted || onlySelect || removeEntities) { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint()); BlockVector3 max = realTo.add(holder .getTransform() .apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()) .toBlockPoint()); - RegionSelector selector = new CuboidRegionSelector(world, realTo, max); - session.setRegionSelector(world, selector); - selector.learnChanges(); - selector.explainRegionAdjust(actor, session); + if (removeEntities) { + editSession.getEntities(new CuboidRegion(realTo, max)).forEach(Entity::remove); + } + if (selectPasted || onlySelect) { + RegionSelector selector = new CuboidRegionSelector(world, realTo, max); + session.setRegionSelector(world, selector); + selector.learnChanges(); + selector.explainRegionAdjust(actor, session); + } } if (onlySelect) { actor.print(Caption.of("worldedit.paste.selected")); @@ -513,14 +522,19 @@ public class ClipboardCommands { boolean pasteBiomes, @ArgFlag(name = 'm', desc = "Only paste blocks matching this mask") @ClipboardMask - Mask sourceMask + Mask sourceMask, + //FAWE start - entity removal + @Switch(name = 'x', desc = "Remove existing entities in the affected region") + boolean removeEntities + //FAWE end + ) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); //FAWE start - use place if (holder.getTransform().isIdentity() && sourceMask == null) { place(actor, world, session, editSession, ignoreAirBlocks, atOrigin, selectPasted, onlySelect, - pasteEntities, pasteBiomes + pasteEntities, pasteBiomes, removeEntities ); return; } @@ -547,21 +561,29 @@ public class ClipboardCommands { messages.addAll(Lists.newArrayList(operation.getStatusMessages())); } - if (selectPasted || onlySelect) { + if (selectPasted || onlySelect || removeEntities) { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3())); Vector3 max = realTo.add(holder .getTransform() .apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())); - final CuboidRegionSelector selector; - if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { - selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); - } else { - selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + + // FAWE start - entity remova;l + if (removeEntities) { + editSession.getEntities(new CuboidRegion(realTo.toBlockPoint(), max.toBlockPoint())).forEach(Entity::remove); + } + if (selectPasted || onlySelect) { + //FAWE end + final CuboidRegionSelector selector; + if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { + selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } else { + selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + } + session.setRegionSelector(world, selector); + selector.learnChanges(); + selector.explainRegionAdjust(actor, session); } - session.setRegionSelector(world, selector); - selector.learnChanges(); - selector.explainRegionAdjust(actor, session); } if (onlySelect) { 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 6b30e9e7e..08f48b265 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 @@ -13,20 +13,22 @@ import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.StringMan; import com.google.common.base.Function; import com.google.common.collect.Lists; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.EditSessionBuilder; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; -import com.sk89q.worldedit.command.util.annotation.AllowedRegion; import com.sk89q.worldedit.command.util.annotation.Confirm; import com.sk89q.worldedit.command.util.annotation.Time; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Identifiable; @@ -80,7 +82,6 @@ public class HistorySubCommands { @Confirm public synchronized void rerun( Player player, World world, RollbackDatabase database, - @AllowedRegion Region[] allowedRegions, @ArgFlag(name = 'u', desc = "String user", def = "me") UUID other, @ArgFlag(name = 'r', def = "0", desc = "radius") @@ -90,7 +91,7 @@ public class HistorySubCommands { @Time long timeDiff ) throws WorldEditException { - rollback(player, world, database, allowedRegions, other, radius, timeDiff, true); + rollback(player, world, database, other, radius, timeDiff, true); } @Command( @@ -102,7 +103,6 @@ public class HistorySubCommands { @Confirm public synchronized void rollback( Player player, World world, RollbackDatabase database, - @AllowedRegion Region[] allowedRegions, @ArgFlag(name = 'u', desc = "String user", def = "") UUID other, @ArgFlag(name = 'r', def = "0", desc = "radius") @@ -149,9 +149,9 @@ public class HistorySubCommands { count++; RollbackOptimizedHistory edit = supplier.get(); if (restore) { - edit.redo(player, allowedRegions); + edit.redo(player); } else { - edit.undo(player, allowedRegions); + edit.undo(player); } String path = edit.getWorld().getName() + "/" + finalOther + "-" + edit.getIndex(); player.print(Caption.of("fawe.worldedit.rollback.rollback.element", path)); @@ -201,8 +201,7 @@ public class HistorySubCommands { .at(summary.maxX, world.getMaxY(), summary.maxZ) ); rollback.setTime(historyFile.lastModified()); - RollbackDatabase db = DBHandler.dbHandler() - .getDatabase(world); + RollbackDatabase db = DBHandler.dbHandler().getDatabase(world); db.logEdit(rollback); actor.print(TextComponent.of("Logging: " + historyFile)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 64e3c8a81..a643742d2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -755,13 +755,7 @@ public class SelectionCommands { } if (setDefaultSelector) { - RegionSelectorType found = null; - for (RegionSelectorType type : RegionSelectorType.values()) { - if (type.getSelectorClass() == newSelector.getClass()) { - found = type; - break; - } - } + RegionSelectorType found = RegionSelectorType.getForSelector(newSelector); if (found != null) { session.setDefaultRegionSelector(found); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 1a382d43c..d82d25394 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -113,8 +113,7 @@ public class FactoryConverter implements ArgumentConverter { ); } - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { + private ParserContext createContext(InjectedValueAccess context) { Actor actor = context.injectedValue(Key.of(Actor.class)) .orElseThrow(() -> new IllegalStateException("No actor")); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); @@ -139,6 +138,13 @@ public class FactoryConverter implements ArgumentConverter { contextTweaker.accept(parserContext); } + return parserContext; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ParserContext parserContext = createContext(context); + try { return SuccessfulConversion.fromSingle( factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) @@ -150,7 +156,9 @@ public class FactoryConverter implements ArgumentConverter { @Override public List getSuggestions(String input, InjectedValueAccess context) { - return factoryExtractor.apply(worldEdit).getSuggestions(input); + ParserContext parserContext = createContext(context); + + return factoryExtractor.apply(worldEdit).getSuggestions(input, parserContext); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 24c674f0b..5c8ff7d6f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -127,13 +127,13 @@ public final class MaskFactory extends AbstractFactory { } @Override - public List getSuggestions(String input) { + public List getSuggestions(String input, final ParserContext parserContext) { final String[] split = input.split(" "); if (split.length > 1) { String prev = input.substring(0, input.lastIndexOf(" ")) + " "; - return super.getSuggestions(split[split.length - 1]).stream().map(s -> prev + s).collect(Collectors.toList()); + return super.getSuggestions(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList()); } - return super.getSuggestions(input); + return super.getSuggestions(input, parserContext); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java index 0e70a18a6..969216896 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java @@ -64,6 +64,7 @@ import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import javax.annotation.Nonnull; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -337,9 +338,10 @@ public class DefaultBlockParser extends InputParser { return SuggestionHelper.getBlockPropertySuggestions(blockType, props); } + @Nonnull private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { //FAWE start - String[] blockAndExtraData = input.trim().split("\\|"); + String[] blockAndExtraData = input.trim().split("(?, Object> blockStates = new HashMap<>(); //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 9dfd373ea..f2d7dc884 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 @@ -25,27 +25,34 @@ import com.fastasyncworldedit.core.extent.HistoryExtent; import com.fastasyncworldedit.core.extent.NullExtent; import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet; import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; 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 org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.List; +import java.util.Set; import java.util.UUID; import static com.google.common.base.Preconditions.checkNotNull; @@ -84,9 +91,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BlockState getBlock(BlockVector3 position) { - //FAWE start - return coordinates - return extent.getBlock(position.getX(), position.getY(), position.getZ()); - //FAWE end + return extent.getBlock(position); } @Override @@ -96,9 +101,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BaseBlock getFullBlock(BlockVector3 position) { - //FAWE start - return coordinates - return extent.getFullBlock(position.getX(), position.getY(), position.getZ()); - //FAWE end + return extent.getFullBlock(position); } //FAWE start @@ -110,9 +113,7 @@ public class AbstractDelegateExtent implements Extent { @Override public BaseBlock getFullBlock(int x, int y, int z) { - //FAWE start - return coordinates return extent.getFullBlock(x, y, z); - //FAWE end } @Override @@ -168,6 +169,7 @@ public class AbstractDelegateExtent implements Extent { } } + //FAWE start @Override public boolean cancel() { ExtentTraverser traverser = new ExtentTraverser<>(this); @@ -188,7 +190,6 @@ public class AbstractDelegateExtent implements Extent { return true; } - //FAWE start @Override public void removeEntity(int x, int y, int z, UUID uuid) { extent.removeEntity(x, y, z, uuid); @@ -225,11 +226,72 @@ public class AbstractDelegateExtent implements Extent { } } + @Override + public boolean isWorld() { + return extent.isWorld(); + } + + @Override + public List> getBlockDistribution(final Region region) { + return extent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(final Region region) { + return extent.getBlockDistributionWithData(region); + } + @Override public int getMaxY() { return extent.getMaxY(); } + @Override + public int countBlocks(final Region region, final Set searchBlocks) { + return extent.countBlocks(region, searchBlocks); + } + + @Override + public int countBlocks(final Region region, final Mask searchMask) { + return extent.countBlocks(region, searchMask); + } + + @Override + public > int setBlocks(final Region region, final B block) throws MaxChangedBlocksException { + return extent.setBlocks(region, block); + } + + @Override + public int setBlocks(final Region region, final Pattern pattern) throws MaxChangedBlocksException { + return extent.setBlocks(region, pattern); + } + + @Override + public > int replaceBlocks( + final Region region, + final Set filter, + final B replacement + ) + throws MaxChangedBlocksException { + return extent.replaceBlocks(region, filter, replacement); + } + + @Override + public int replaceBlocks(final Region region, final Set filter, final Pattern pattern) throws + MaxChangedBlocksException { + return extent.replaceBlocks(region, filter, pattern); + } + + @Override + public int replaceBlocks(final Region region, final Mask mask, final Pattern pattern) throws MaxChangedBlocksException { + return extent.replaceBlocks(region, mask, pattern); + } + + @Override + public int setBlocks(final Set vset, final Pattern pattern) { + return extent.setBlocks(vset, pattern); + } + @Override public int getMinY() { return extent.getMinY(); @@ -295,22 +357,26 @@ public class AbstractDelegateExtent implements Extent { return this; } + @Override + public T apply(final Region region, final T filter, final boolean full) { + return extent.apply(region, filter, full); + } + //FAWE end + protected Operation commitBefore() { return null; } - @Override - public BiomeType getBiomeType(int x, int y, int z) { - return extent.getBiomeType(x, y, z); - } - @Override public BiomeType getBiome(BlockVector3 position) { return extent.getBiome(position); } - /* - History - */ + + //FAWE start + @Override + public BiomeType getBiomeType(int x, int y, int z) { + return extent.getBiomeType(x, y, z); + } @Override public int getEmittedLight(int x, int y, int z) { @@ -341,13 +407,15 @@ public class AbstractDelegateExtent implements Extent { new ExtentTraverser<>(this).setNext(new HistoryExtent(extent, changeSet)); } } + //FAWE end @Override public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { - return extent.setBlock(position.getX(), position.getY(), position.getZ(), block); + return extent.setBlock(position, block); } + //FAWE start @Override public > boolean setBlock( int x, int y, @@ -360,6 +428,7 @@ public class AbstractDelegateExtent implements Extent { public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile)); } + //FAWE end @Override public boolean fullySupports3DBiomes() { @@ -367,13 +436,14 @@ public class AbstractDelegateExtent implements Extent { } @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return extent.setBiome(x, y, z, biome); + public boolean setBiome(BlockVector3 position, BiomeType biome) { + return extent.setBiome(position, biome); } + //FAWE start @Override - public boolean setBiome(BlockVector3 position, BiomeType biome) { - return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome); + public boolean setBiome(int x, int y, int z, BiomeType biome) { + return extent.setBiome(x, y, z, biome); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java index f569acd00..ca2bfd965 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java @@ -235,4 +235,11 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat }; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + return new ForgetfulExtentBuffer(extent, mask.copy()); + } + //FAWE end + } 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 15d6365e7..76e866c33 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 @@ -73,7 +73,10 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl /** * Creates a new {@link ReadOnlyClipboard}. + * + * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region)} */ + @Deprecated static Clipboard create(Region region) { checkNotNull(region); checkNotNull( @@ -95,7 +98,10 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl * - {@link DiskOptimizedClipboard} * - {@link CPUOptimizedClipboard} * - {@link MemoryOptimizedClipboard} + * + * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)} */ + @Deprecated static Clipboard create(Region region, UUID uuid) { if (Settings.settings().CLIPBOARD.USE_DISK) { return new DiskOptimizedClipboard(region, uuid); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.java new file mode 100644 index 000000000..f94216669 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicLoadException.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.extent.clipboard.io; + +import com.sk89q.worldedit.util.formatting.text.Component; + +/** + * Raised when a known exception occurs during schematic load. + */ +public final class SchematicLoadException extends RuntimeException { + + private final Component message; + + public SchematicLoadException(Component message) { + this.message = message; + } + + /** + * Get the message of this exception as a rich text component. + * + * @return The rich message + */ + public Component getRichMessage() { + return this.message; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index 464ef3e4f..83d8c3007 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.fastasyncworldedit.core.configuration.Caption; import com.google.common.collect.Maps; import com.sk89q.jnbt.AdventureNBTConverter; import com.sk89q.jnbt.ByteArrayTag; @@ -46,6 +47,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -137,9 +139,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { BlockArrayClipboard clip = readVersion1(schematicTag); return readVersion2(clip, schematicTag); } - throw new IOException("This schematic version is not supported; Version: " + schematicVersion + ", DataVersion: " + dataVersion + "." + - "It's very likely your schematic has an invalid file extension, if the schematic has been created on a version lower than" + - "1.13.2, the extension MUST be `.schematic`, elsewise the schematic can't be read properly."); + throw new SchematicLoadException(Caption.of("worldedit.schematic.load.unsupported-version", + TextComponent.of(schematicVersion))); } @Override @@ -169,6 +170,13 @@ public class SpongeSchematicReader extends NBTSchematicReader { // Check Map schematic = schematicTag.getValue(); + // Be lenient about the specific nesting level of the Schematic tag + // Also allows checking the version from newer versions of the specification + if (schematic.size() == 1 && schematic.containsKey("Schematic")) { + schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); + schematic = schematicTag.getValue(); + } + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); return schematicTag; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 55340bb07..237c0b220 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -86,6 +86,11 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde priorityMap.put(BlockTypes.WHITE_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.YELLOW_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.GRASS, PlacementPriority.LAST); + // Keep "grass" for <1.20.3 compat + @SuppressWarnings("deprecation") + BlockType grass = BlockTypes.GRASS; + priorityMap.put(grass, PlacementPriority.LAST); + priorityMap.put(BlockTypes.SHORT_GRASS, PlacementPriority.LAST); priorityMap.put(BlockTypes.TALL_GRASS, PlacementPriority.LAST); priorityMap.put(BlockTypes.ROSE_BUSH, PlacementPriority.LAST); priorityMap.put(BlockTypes.DANDELION, PlacementPriority.LAST); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java index 1b806c7d8..bc498711b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/validation/DataValidatorExtent.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; 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.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -34,7 +35,8 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class DataValidatorExtent extends AbstractDelegateExtent { - private final World world; + private final int minY; + private final int maxY; /** * Create a new instance. @@ -43,16 +45,27 @@ public class DataValidatorExtent extends AbstractDelegateExtent { * @param world the world */ public DataValidatorExtent(Extent extent, World world) { + this(extent, checkNotNull(world).getMinY(), world.getMaxY()); + } + + /** + * Create a new instance. + * + * @param extent The extent + * @param minY The minimum Y height to allow (inclusive) + * @param maxY The maximum Y height to allow (inclusive) + */ + public DataValidatorExtent(Extent extent, int minY, int maxY) { super(extent); - checkNotNull(world); - this.world = world; + this.minY = minY; + this.maxY = maxY; } @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { final int y = location.getBlockY(); final BlockType type = block.getBlockType(); - if (y < world.getMinY() || y > world.getMaxY()) { + if (y < minY || y > maxY) { return false; } @@ -64,4 +77,15 @@ public class DataValidatorExtent extends AbstractDelegateExtent { return super.setBlock(location, block); } + @Override + public boolean setBiome(BlockVector3 location, BiomeType biome) { + final int y = location.getBlockY(); + + if (y < minY || y > maxY) { + return false; + } + + return super.setBiome(location, biome); + } + } 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 5ea9aa66e..a1ddb2240 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 @@ -29,6 +29,7 @@ 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.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; /** @@ -103,7 +104,12 @@ public class FloraGenerator implements RegionFunction { */ public static Pattern getTemperatePattern() { RandomPattern pattern = new RandomPattern(); - pattern.add(BlockTypes.GRASS.getDefaultState(), 300); + BlockType grass = BlockTypes.SHORT_GRASS; + if (grass == null) { + // Fallback for <1.20.3 compat + grass = BlockTypes.GRASS; + } + pattern.add(grass.getDefaultState(), 300); pattern.add(BlockTypes.POPPY.getDefaultState(), 5); pattern.add(BlockTypes.DANDELION.getDefaultState(), 5); return pattern; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java index 301f2104c..dfe1841d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BoundedHeightMask.java @@ -41,7 +41,7 @@ public class BoundedHeightMask extends AbstractMask { * @param maxY the maximum Y (must be equal to or greater than minY) */ public BoundedHeightMask(int minY, int maxY) { - checkArgument(minY <= maxY, "minY <= maxY required"); + checkArgument(minY <= maxY, "minY <= maxY required. minY:" + minY + " and maxY:" + maxY + " were given."); this.minY = minY; this.maxY = maxY; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java index 49e7f5472..863cf1e25 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentBufferedCompositePattern.java @@ -25,6 +25,8 @@ import com.sk89q.worldedit.extent.buffer.ExtentBuffer; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.Arrays; + import static com.google.common.base.Preconditions.checkArgument; /** @@ -64,4 +66,12 @@ public class ExtentBufferedCompositePattern extends AbstractExtentPattern { return lastBlock; } + //FAWE - stateful pattern + @Override + public Pattern fork() { + final Pattern[] forkedPatterns = Arrays.stream(patterns).map(Pattern::fork).toArray(Pattern[]::new); + return new ExtentBufferedCompositePattern(getExtent(), forkedPatterns); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 801b07a65..ab284c0cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -59,6 +59,11 @@ public interface Pattern extends Filter { apply(block, block, block); } + @Override + default Pattern fork() { // covariant return type + return this; + } + //FAWE end /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java index 0568fd5b8..7656a1656 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RandomPattern.java @@ -27,10 +27,10 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -39,11 +39,10 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class RandomPattern extends AbstractPattern { - //FAWE start - SimpleRandom > Random, LHS

> List + //FAWE start - SimpleRandom > Random, RandomCollection private final SimpleRandom random; - private Map weights = new HashMap<>(); + private final List> weights; private RandomCollection collection; - private LinkedHashSet patterns = new LinkedHashSet<>(); //FAWE end //FAWE start @@ -53,6 +52,7 @@ public class RandomPattern extends AbstractPattern { public RandomPattern(SimpleRandom random) { this.random = random; + this.weights = new ArrayList<>(); } /** @@ -63,9 +63,14 @@ public class RandomPattern extends AbstractPattern { */ public RandomPattern(SimpleRandom random, RandomPattern parent) { this.random = random; - this.weights = parent.weights; - this.collection = RandomCollection.of(weights, random); - this.patterns = parent.patterns; + this.weights = new ArrayList<>(parent.weights); + this.collection = RandomCollection.of(weights); + } + + private RandomPattern(SimpleRandom random, List> weights) { + this.random = random; + this.weights = weights; + this.collection = RandomCollection.of(weights); } //FAWE end @@ -80,18 +85,15 @@ public class RandomPattern extends AbstractPattern { */ public void add(Pattern pattern, double chance) { checkNotNull(pattern); - //FAWE start - Double, weights, patterns and collection - Double existingWeight = weights.get(pattern); - if (existingWeight != null) { - chance += existingWeight; - } - weights.put(pattern, chance); - collection = RandomCollection.of(weights, random); - this.patterns.add(pattern); + //FAWE start - Double, weights, repeating patterns, and collection + this.weights.add(new RandomCollection.Weighted<>(pattern, chance)); + this.collection = RandomCollection.of(weights); } public Set getPatterns() { - return patterns; + return this.weights.stream() + .map(RandomCollection.Weighted::value) + .collect(Collectors.toSet()); } public RandomCollection getCollection() { @@ -100,13 +102,21 @@ public class RandomPattern extends AbstractPattern { @Override public BaseBlock applyBlock(BlockVector3 position) { - return collection.next(position.getBlockX(), position.getBlockY(), position.getBlockZ()).applyBlock(position); + return collection.next(this.random, position.getBlockX(), position.getBlockY(), position.getBlockZ()).applyBlock(position); } @Override public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { - return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); + return collection.next(this.random, get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, get, set); } + + @Override + public Pattern fork() { + List> newWeights = new ArrayList<>(); + this.weights.forEach((w) -> newWeights.add(new RandomCollection.Weighted<>(w.value().fork(), w.weight()))); + return new RandomPattern(this.random, newWeights); + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java index 3d834f76b..b328e78ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/StateApplyingPattern.java @@ -29,13 +29,16 @@ import com.sk89q.worldedit.world.block.BlockType; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import static com.sk89q.worldedit.blocks.Blocks.resolveProperties; public class StateApplyingPattern extends AbstractExtentPattern { private final Map states; - private final Map, Object>> cache = Maps.newHashMap(); + //FAWE - avoid race conditions + private final Map, Object>> cache = new ConcurrentHashMap<>(); + //FAWE end public StateApplyingPattern(Extent extent, Map statesToSet) { super(extent); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index 3f5bfafb5..a0c5eb328 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -36,6 +36,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.extent.clipboard.io.SchematicLoadException; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.formatting.text.Component; @@ -187,6 +188,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { throw newCommandException(Caption.of("worldedit.error.file-aborted"), e); } + @ExceptionMatch + public void convert(SchematicLoadException e) throws CommandException { + throw newCommandException(e.getRichMessage(), e); + } + @ExceptionMatch public void convert(WorldEditException e) throws CommandException { throw newCommandException(e.getRichMessage(), e); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index b7ce1acf3..23ba96a88 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.antlr.ExpressionLexer; import com.sk89q.worldedit.antlr.ExpressionParser; import com.sk89q.worldedit.internal.expression.invoke.ExpressionCompiler; +import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -199,7 +200,9 @@ public class Expression implements Cloneable { //FAWE start public Expression clone() { - return new Expression(initialExpression, new HashSet<>(providedSlots)); + Expression expression = new Expression(initialExpression, new HashSet<>(providedSlots)); + expression.setEnvironment(getEnvironment().clone()); + return expression; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java index 061a520a9..5e44d9da1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.internal.expression; /** * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. */ -public interface ExpressionEnvironment { +public interface ExpressionEnvironment extends Cloneable { int getBlockType(double x, double y, double z); @@ -36,4 +36,7 @@ public interface ExpressionEnvironment { int getBlockDataRel(double x, double y, double z); + // FAWE start + ExpressionEnvironment clone(); + // FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index ef4299b33..237dd1c4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -96,9 +96,14 @@ public abstract class AbstractFactory { throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); } + @Deprecated public List getSuggestions(String input) { + return getSuggestions(input, new ParserContext()); + } + + public List getSuggestions(String input, ParserContext context) { return parsers.stream().flatMap( - p -> p.getSuggestions(input) + p -> p.getSuggestions(input, context) ).collect(Collectors.toList()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index 87829a272..57ec3a247 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -45,9 +45,22 @@ public abstract class InputParser { * Gets a stream of suggestions of input to this parser. * * @return a stream of suggestions + * @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, ParserContext)} */ + @Deprecated public Stream getSuggestions(String input) { return Stream.empty(); } + /** + * Gets a stream of suggestions of input to this parser. + * + * @param input The string input + * @param context The parser context + * + * @return a stream of suggestions + */ + public Stream getSuggestions(String input, ParserContext context) { + return getSuggestions(input); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index c06e0968e..02ee75d44 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -195,6 +195,33 @@ public class AffineTransform implements Transform, Serializable { // =================================================================== // general methods + /** + * Returns the affine transform created by applying first the affine + * transform given by the parameters, then this affine transform. + * + * @return the composition this * that + */ + public AffineTransform concatenate(double o00, double o01, double o02, double o03, + double o10, double o11, double o12, double o13, + double o20, double o21, double o22, double o23) { + double n00 = m00 * o00 + m01 * o10 + m02 * o20; + double n01 = m00 * o01 + m01 * o11 + m02 * o21; + double n02 = m00 * o02 + m01 * o12 + m02 * o22; + double n03 = m00 * o03 + m01 * o13 + m02 * o23 + m03; + double n10 = m10 * o00 + m11 * o10 + m12 * o20; + double n11 = m10 * o01 + m11 * o11 + m12 * o21; + double n12 = m10 * o02 + m11 * o12 + m12 * o22; + double n13 = m10 * o03 + m11 * o13 + m12 * o23 + m13; + double n20 = m20 * o00 + m21 * o10 + m22 * o20; + double n21 = m20 * o01 + m21 * o11 + m22 * o21; + double n22 = m20 * o02 + m21 * o12 + m22 * o22; + double n23 = m20 * o03 + m21 * o13 + m22 * o23 + m23; + return new AffineTransform( + n00, n01, n02, n03, + n10, n11, n12, n13, + n20, n21, n22, n23); + } + /** * Returns the affine transform created by applying first the affine * transform given by {@code that}, then this affine transform. @@ -203,22 +230,10 @@ public class AffineTransform implements Transform, Serializable { * @return the composition this * that */ public AffineTransform concatenate(AffineTransform that) { - double n00 = m00 * that.m00 + m01 * that.m10 + m02 * that.m20; - double n01 = m00 * that.m01 + m01 * that.m11 + m02 * that.m21; - double n02 = m00 * that.m02 + m01 * that.m12 + m02 * that.m22; - double n03 = m00 * that.m03 + m01 * that.m13 + m02 * that.m23 + m03; - double n10 = m10 * that.m00 + m11 * that.m10 + m12 * that.m20; - double n11 = m10 * that.m01 + m11 * that.m11 + m12 * that.m21; - double n12 = m10 * that.m02 + m11 * that.m12 + m12 * that.m22; - double n13 = m10 * that.m03 + m11 * that.m13 + m12 * that.m23 + m13; - double n20 = m20 * that.m00 + m21 * that.m10 + m22 * that.m20; - double n21 = m20 * that.m01 + m21 * that.m11 + m22 * that.m21; - double n22 = m20 * that.m02 + m21 * that.m12 + m22 * that.m22; - double n23 = m20 * that.m03 + m21 * that.m13 + m22 * that.m23 + m23; - return new AffineTransform( - n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23 + return concatenate( + that.m00, that.m01, that.m02, that.m03, + that.m10, that.m11, that.m12, that.m13, + that.m20, that.m21, that.m22, that.m23 ); } @@ -258,40 +273,37 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform translate(double x, double y, double z) { - return concatenate(new AffineTransform(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z)); + return concatenate(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z); } public AffineTransform rotateX(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - 1, 0, 0, 0, - 0, cot, -sit, 0, - 0, sit, cot, 0 - )); + 1, 0, 0, 0, + 0, cot, -sit, 0, + 0, sit, cot, 0 + ); } public AffineTransform rotateY(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - cot, 0, sit, 0, - 0, 1, 0, 0, - -sit, 0, cot, 0 - )); + cot, 0, sit, 0, + 0, 1, 0, 0, + -sit, 0, cot, 0 + ); } public AffineTransform rotateZ(double theta) { double cot = MathUtils.dCos(theta); double sit = MathUtils.dSin(theta); return concatenate( - new AffineTransform( - cot, -sit, 0, 0, - sit, cot, 0, 0, - 0, 0, 1, 0 - )); + cot, -sit, 0, 0, + sit, cot, 0, 0, + 0, 0, 1, 0 + ); } public AffineTransform scale(double s) { @@ -299,7 +311,7 @@ public class AffineTransform implements Transform, Serializable { } public AffineTransform scale(double sx, double sy, double sz) { - return concatenate(new AffineTransform(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0)); + return concatenate(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0); } public AffineTransform scale(Vector3 vec) { @@ -352,9 +364,9 @@ public class AffineTransform implements Transform, Serializable { //FAWE start - check other identity if (other instanceof Identity || other.isIdentity()) { return this; - } else if (other instanceof AffineTransform) { + } else if (other instanceof AffineTransform otherTransform) { //FAWE end - return concatenate((AffineTransform) other); + return concatenate(otherTransform); } else { return new CombinedTransform(this, other); } 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 cc2f03aa2..d04e5aa8c 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 @@ -22,7 +22,6 @@ package com.sk89q.worldedit.regions; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.math.BlockVectorSet; -import com.fastasyncworldedit.core.math.MutableBlockVector2; import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IChunk; @@ -805,7 +804,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return set; } trimY(set, minY, maxY, true); - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { @@ -868,8 +868,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } set.setBlocks(layer, arr); } - - trimNBT(set, this::contains); + final BlockVector3 chunkPos = BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } return null; @@ -893,7 +893,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return null; } trimY(set, minY, maxY, false); - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); return set; } if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { @@ -943,7 +944,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { } set.setBlocks(layer, arr); } - trimNBT(set, bv3 -> !this.contains(bv3)); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos))); return set; } return set; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java index 03b38a55c..6439d6079 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CylinderRegion.java @@ -141,7 +141,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { */ public void setRadius(Vector2 radius) { this.radius = radius.add(0.5, 0.5); - this.radiusInverse = Vector2.ONE.divide(radius); + this.radiusInverse = Vector2.ONE.divide(this.radius); } /** @@ -413,11 +413,12 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion { final IChunk chunk, final Filter filter, final ChunkFilterBlock block, final IChunkGet get, final IChunkSet set, boolean full ) { - int bcx = chunk.getX() >> 4; - int bcz = chunk.getZ() >> 4; + int bcx = chunk.getX() << 4; + int bcz = chunk.getZ() << 4; int tcx = bcx + 15; int tcz = bcz + 15; - if (contains(bcx, bcz) && contains(tcx, tcz)) { + // must contain all 4 corners for fast path + if (contains(bcx, bcz) && contains(tcx, tcz) && contains(bcx, tcz) && contains(tcx, bcz)) { filter(chunk, filter, block, get, set, minY, maxY, full); return; } 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 b89536520..d2fa35310 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 @@ -425,7 +425,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } } if (processExtra) { - trimNBT(set, this::contains); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos))); } return set; } else { @@ -477,7 +478,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } } if (processExtra) { - trimNBT(set, bv3 -> !this.contains(bv3)); + BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0); + trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos))); } return set; } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java index 61e46aeab..5c8655893 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/RegionSelectorType.java @@ -19,8 +19,14 @@ package com.sk89q.worldedit.regions.selector; +import com.fastasyncworldedit.core.regions.selector.FuzzyRegionSelector; +import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector; import com.sk89q.worldedit.regions.RegionSelector; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + /** * An enum of default region selector types. */ @@ -32,7 +38,21 @@ public enum RegionSelectorType { SPHERE(SphereRegionSelector.class), ELLIPSOID(EllipsoidRegionSelector.class), POLYGON(Polygonal2DRegionSelector.class), - CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class); + CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class), + //FAWE start + POLYHEDRAL(PolyhedralRegionSelector.class), + FUZZY(FuzzyRegionSelector.class); + //FAWE end + + //FAWE start + private static final Map, RegionSelectorType> VALUE_MAP = new HashMap<>(); + + static { + for (RegionSelectorType type : values()) { + VALUE_MAP.put(type.getSelectorClass(), type); + } + } + //FAWE end private final Class selectorClass; @@ -40,6 +60,19 @@ public enum RegionSelectorType { this.selectorClass = selectorClass; } + //FAWE start + /** + * Get a {@link RegionSelectorType} for the given {@link RegionSelector} + * + * @param selector Region selector to get type enum for + * @since TODO + */ + @Nullable + public static RegionSelectorType getForSelector(RegionSelector selector) { + return VALUE_MAP.get(selector.getClass()); + } + //FAWE end + /** * Get the selector class. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java index 15e93c7db..2284b9733 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.math.Vector3; public class WorldEditExpressionEnvironment implements ExpressionEnvironment { + private static final Vector3 BLOCK_CENTER_OFFSET = Vector3.at(0.5, 0.5, 0.5); + private final Vector3 unit; private final Vector3 zero2; //FAWE start - MutableVector3 @@ -42,7 +44,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) { this.extent = extent; this.unit = unit; - this.zero2 = zero.add(0.5, 0.5, 0.5); + this.zero2 = zero.add(BLOCK_CENTER_OFFSET); } public BlockVector3 toWorld(double x, double y, double z) { @@ -83,7 +85,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { @SuppressWarnings("deprecation") @Override public int getBlockDataRel(double x, double y, double z) { - return extent.getBlock(toWorld(x, y, z)).getBlockType().getLegacyCombinedId() & 0xF; + return extent.getBlock(toWorldRel(x, y, z).toBlockPoint()).getBlockType().getLegacyCombinedId() & 0xF; } //FAWE start @@ -94,10 +96,13 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment { public Vector3 toWorldRel(double x, double y, double z) { return current.add(x, y, z); } + + public WorldEditExpressionEnvironment clone() { + return new WorldEditExpressionEnvironment(extent, unit, zero2.subtract(BLOCK_CENTER_OFFSET)); + } //FAWe end public void setCurrentBlock(Vector3 current) { this.current = current; } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index 9b9a9a6e5..e5d05ee6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -19,10 +19,14 @@ package com.sk89q.worldedit.util.gson; +import com.fastasyncworldedit.core.util.gson.ItemTypeAdapter; +import com.fastasyncworldedit.core.util.gson.RegionSelectorAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.world.item.ItemType; /** * Utility methods for Google's GSON library. @@ -41,6 +45,10 @@ public final class GsonUtil { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); + //FAWE start + gsonBuilder.registerTypeAdapter(RegionSelector.class, new RegionSelectorAdapter()); + gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); + //FAWE end return gsonBuilder; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java index 47905dcd4..4d1bde5f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -48,6 +48,7 @@ public final class BlockCategories { public static final BlockCategory BIG_DRIPLEAF_PLACEABLE = get("minecraft:big_dripleaf_placeable"); public static final BlockCategory BIRCH_LOGS = get("minecraft:birch_logs"); public static final BlockCategory BUTTONS = get("minecraft:buttons"); + public static final BlockCategory CAMEL_SAND_STEP_SOUND_BLOCKS = get("minecraft:camel_sand_step_sound_blocks"); public static final BlockCategory CAMPFIRES = get("minecraft:campfires"); public static final BlockCategory CANDLE_CAKES = get("minecraft:candle_cakes"); public static final BlockCategory CANDLES = get("minecraft:candles"); @@ -60,6 +61,7 @@ public final class BlockCategories { public static final BlockCategory COAL_ORES = get("minecraft:coal_ores"); public static final BlockCategory COMBINATION_STEP_SOUND_BLOCKS = get("minecraft:combination_step_sound_blocks"); public static final BlockCategory COMPLETES_FIND_TREE_TUTORIAL = get("minecraft:completes_find_tree_tutorial"); + public static final BlockCategory CONCRETE_POWDER = get("minecraft:concrete_powder"); public static final BlockCategory CONVERTABLE_TO_MUD = get("minecraft:convertable_to_mud"); public static final BlockCategory COPPER_ORES = get("minecraft:copper_ores"); public static final BlockCategory CORAL_BLOCKS = get("minecraft:coral_blocks"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index f08675fc5..5059c737a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -178,9 +178,18 @@ public class BlockState implements BlockStateHolder, Pattern { String name = property.getName(); charSequence.setSubstring(propStrStart + name.length() + 2, state.length() - 1); - int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence); - if (index != -1) { - return type.withPropertyId(index); + try { + int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence); + if (index != -1) { + return type.withPropertyId(index); + } + } catch (Exception e) { + throw new InputParseException(Caption.of( + "fawe.error.invalid-block-state-property", + TextComponent.of(charSequence.toString()), + TextComponent.of(name), + TextComponent.of(state) + ), e); } } int stateId; @@ -200,7 +209,17 @@ public class BlockState implements BlockStateHolder, Pattern { case ',': { charSequence.setSubstring(last, i); if (property != null) { - int index = property.getIndexFor(charSequence); + int index; + try { + index = property.getIndexFor(charSequence); + } catch (Exception e) { + throw new InputParseException(Caption.of( + "fawe.error.invalid-block-state-property", + TextComponent.of(charSequence.toString()), + TextComponent.of(property.getName()), + TextComponent.of(state) + ), e); + } if (index == -1) { throw SuggestInputParseException.of(charSequence.toString(), (List) property.getValues()); } 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 0cd3f55e5..4b3204be4 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 @@ -415,6 +415,8 @@ public final class BlockTypes { @Nullable public static final BlockType CHISELED_BOOKSHELF = init(); @Nullable + public static final BlockType CHISELED_COPPER = init(); + @Nullable public static final BlockType CHISELED_DEEPSLATE = init(); @Nullable public static final BlockType CHISELED_NETHER_BRICKS = init(); @@ -429,6 +431,10 @@ public final class BlockTypes { @Nullable public static final BlockType CHISELED_STONE_BRICKS = init(); @Nullable + public static final BlockType CHISELED_TUFF = init(); + @Nullable + public static final BlockType CHISELED_TUFF_BRICKS = init(); + @Nullable public static final BlockType CHORUS_FLOWER = init(); @Nullable public static final BlockType CHORUS_PLANT = init(); @@ -471,6 +477,12 @@ public final class BlockTypes { @Nullable public static final BlockType COPPER_BLOCK = init(); @Nullable + public static final BlockType COPPER_BULB = init(); + @Nullable + public static final BlockType COPPER_DOOR = init(); + @Nullable + public static final BlockType COPPER_GRATE = init(); + @Nullable public static final BlockType CORNFLOWER = init(); @Nullable public static final BlockType CRACKED_DEEPSLATE_BRICKS = init(); @@ -673,6 +685,8 @@ public final class BlockTypes { @Nullable public static final BlockType DEEPSLATE_COPPER_ORE = init(); @Nullable + public static final BlockType COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType DEEPSLATE_DIAMOND_ORE = init(); @Nullable public static final BlockType DEEPSLATE_EMERALD_ORE = init(); @@ -733,6 +747,8 @@ public final class BlockTypes { @Nullable public static final BlockType ENDER_CHEST = init(); @Nullable + public static final BlockType EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final BlockType END_GATEWAY = init(); @Nullable public static final BlockType END_PORTAL = init(); @@ -753,6 +769,14 @@ public final class BlockTypes { @Nullable public static final BlockType EXPOSED_COPPER = init(); @Nullable + public static final BlockType EXPOSED_COPPER_BULB = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final BlockType EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType EXPOSED_CUT_COPPER = init(); @Nullable public static final BlockType EXPOSED_CUT_COPPER_SLAB = init(); @@ -808,7 +832,7 @@ public final class BlockTypes { public static final BlockType GRANITE_STAIRS = init(); @Nullable public static final BlockType GRANITE_WALL = init(); - @Nullable + @Nullable @Deprecated public static final BlockType GRASS = init(); @Nullable public static final BlockType GRASS_BLOCK = init(); @@ -901,6 +925,8 @@ public final class BlockTypes { @Nullable public static final BlockType INFESTED_CRACKED_STONE_BRICKS = init(); @Nullable + public static final BlockType CRAFTER = init(); + @Nullable public static final BlockType INFESTED_DEEPSLATE = init(); @Nullable public static final BlockType INFESTED_MOSSY_STONE_BRICKS = init(); @@ -1293,8 +1319,18 @@ public final class BlockTypes { @Nullable public static final BlockType OXEYE_DAISY = init(); @Nullable + public static final BlockType OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final BlockType OXIDIZED_COPPER = init(); @Nullable + public static final BlockType OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final BlockType OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType OXIDIZED_CUT_COPPER = init(); @Nullable public static final BlockType OXIDIZED_CUT_COPPER_SLAB = init(); @@ -1411,6 +1447,14 @@ public final class BlockTypes { @Nullable public static final BlockType POLISHED_GRANITE_STAIRS = init(); @Nullable + public static final BlockType POLISHED_TUFF = init(); + @Nullable + public static final BlockType POLISHED_TUFF_SLAB = init(); + @Nullable + public static final BlockType POLISHED_TUFF_STAIRS = init(); + @Nullable + public static final BlockType POLISHED_TUFF_WALL = init(); + @Nullable public static final BlockType POPPY = init(); @Nullable public static final BlockType POTATOES = init(); @@ -1667,6 +1711,8 @@ public final class BlockTypes { @Nullable public static final BlockType SEAGRASS = init(); @Nullable + public static final BlockType SHORT_GRASS = init(); + @Nullable public static final BlockType SEA_LANTERN = init(); @Nullable public static final BlockType SEA_PICKLE = init(); @@ -1874,6 +1920,8 @@ public final class BlockTypes { @Nullable public static final BlockType TRAPPED_CHEST = init(); @Nullable + public static final BlockType TRIAL_SPAWNER = init(); + @Nullable public static final BlockType TRIPWIRE = init(); @Nullable public static final BlockType TRIPWIRE_HOOK = init(); @@ -1888,6 +1936,20 @@ public final class BlockTypes { @Nullable public static final BlockType TUFF = init(); @Nullable + public static final BlockType TUFF_BRICK_SLAB = init(); + @Nullable + public static final BlockType TUFF_BRICK_STAIRS = init(); + @Nullable + public static final BlockType TUFF_BRICK_WALL = init(); + @Nullable + public static final BlockType TUFF_BRICKS = init(); + @Nullable + public static final BlockType TUFF_SLAB = init(); + @Nullable + public static final BlockType TUFF_STAIRS = init(); + @Nullable + public static final BlockType TUFF_WALL = init(); + @Nullable public static final BlockType TURTLE_EGG = init(); @Nullable public static final BlockType TWISTING_VINES = init(); @@ -1947,16 +2009,36 @@ public final class BlockTypes { @Nullable public static final BlockType WATER_CAULDRON = init(); @Nullable + public static final BlockType WAXED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_COPPER_BLOCK = init(); @Nullable + public static final BlockType WAXED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_CUT_COPPER_STAIRS = init(); + @ Nullable + public static final BlockType WAXED_EXPOSED_CHISELED_COPPER = init(); @Nullable public static final BlockType WAXED_EXPOSED_COPPER = init(); @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_EXPOSED_CUT_COPPER_SLAB = init(); @@ -1965,22 +2047,52 @@ public final class BlockTypes { @Nullable public static final BlockType WAXED_OXIDIZED_COPPER = init(); @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable + public static final BlockType WAXED_OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_OXIDIZED_CUT_COPPER_STAIRS = init(); @Nullable + public static final BlockType WAXED_WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WAXED_WEATHERED_COPPER = init(); @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_BULB = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WAXED_WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER = init(); @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_SLAB = init(); @Nullable public static final BlockType WAXED_WEATHERED_CUT_COPPER_STAIRS = init(); @Nullable + public static final BlockType WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final BlockType WEATHERED_COPPER = init(); @Nullable + public static final BlockType WEATHERED_COPPER_BULB = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final BlockType WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final BlockType WEATHERED_CUT_COPPER = init(); @Nullable public static final BlockType WEATHERED_CUT_COPPER_SLAB = init(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java index 4b650ac07..f981593fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -51,6 +51,8 @@ public final class EntityTypes { @Nullable public static final EntityType BOAT = get("minecraft:boat"); @Nullable + public static final EntityType BREEZE = get("minecraft:breeze"); + @Nullable public static final EntityType CAMEL = get("minecraft:camel"); @Nullable public static final EntityType CAT = get("minecraft:cat"); @@ -259,6 +261,8 @@ public final class EntityTypes { @Nullable public static final EntityType WARDEN = get("minecraft:warden"); @Nullable + public static final EntityType WIND_CHARGE = get("minecraft:wind_charge"); + @Nullable public static final EntityType WITCH = get("minecraft:witch"); @Nullable public static final EntityType WITHER = get("minecraft:wither"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 5a1e7653f..16a65c308 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -79,7 +79,7 @@ public class ItemType implements RegistryItem, Keyed { } //FAWE start - private int internalId; + private transient int internalId; @Override public void setInternalId(int internalId) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index 663cf5c61..b8064bb94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -319,6 +319,8 @@ public final class ItemTypes { @Nullable public static final ItemType BREAD = init(); @Nullable + public static final ItemType BREEZE_SPAWN_EGG = init(); + @Nullable public static final ItemType BREWER_POTTERY_SHERD = init(); @Nullable public static final ItemType BREWING_STAND = init(); @@ -468,6 +470,8 @@ public final class ItemTypes { @Nullable public static final ItemType CHISELED_BOOKSHELF = init(); @Nullable + public static final ItemType CHISELED_COPPER = init(); + @Nullable public static final ItemType CHISELED_DEEPSLATE = init(); @Nullable public static final ItemType CHISELED_NETHER_BRICKS = init(); @@ -482,6 +486,10 @@ public final class ItemTypes { @Nullable public static final ItemType CHISELED_STONE_BRICKS = init(); @Nullable + public static final ItemType CHISELED_TUFF = init(); + @Nullable + public static final ItemType CHISELED_TUFF_BRICKS = init(); + @Nullable public static final ItemType CHORUS_FLOWER = init(); @Nullable public static final ItemType CHORUS_FRUIT = init(); @@ -560,10 +568,18 @@ public final class ItemTypes { @Nullable public static final ItemType COPPER_BLOCK = init(); @Nullable + public static final ItemType COPPER_BULB = init(); + @Nullable + public static final ItemType COPPER_DOOR = init(); + @Nullable + public static final ItemType COPPER_GRATE = init(); + @Nullable public static final ItemType COPPER_INGOT = init(); @Nullable public static final ItemType COPPER_ORE = init(); @Nullable + public static final ItemType COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType CORNFLOWER = init(); @Nullable public static final ItemType COW_SPAWN_EGG = init(); @@ -578,6 +594,8 @@ public final class ItemTypes { @Nullable public static final ItemType CRACKED_STONE_BRICKS = init(); @Nullable + public static final ItemType CRAFTER = init(); + @Nullable public static final ItemType CRAFTING_TABLE = init(); @Nullable public static final ItemType CREEPER_BANNER_PATTERN = init(); @@ -903,8 +921,18 @@ public final class ItemTypes { @Nullable public static final ItemType EXPLORER_POTTERY_SHERD = init(); @Nullable + public static final ItemType EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final ItemType EXPOSED_COPPER = init(); @Nullable + public static final ItemType EXPOSED_COPPER_BULB = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final ItemType EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType EXPOSED_CUT_COPPER = init(); @Nullable public static final ItemType EXPOSED_CUT_COPPER_SLAB = init(); @@ -1036,7 +1064,7 @@ public final class ItemTypes { public static final ItemType GRANITE_STAIRS = init(); @Nullable public static final ItemType GRANITE_WALL = init(); - @Nullable + @Nullable @Deprecated public static final ItemType GRASS = init(); @Nullable public static final ItemType GRASS_BLOCK = init(); @@ -1670,8 +1698,18 @@ public final class ItemTypes { @Nullable public static final ItemType OXEYE_DAISY = init(); @Nullable + public static final ItemType OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final ItemType OXIDIZED_COPPER = init(); @Nullable + public static final ItemType OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final ItemType OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType OXIDIZED_CUT_COPPER = init(); @Nullable public static final ItemType OXIDIZED_CUT_COPPER_SLAB = init(); @@ -1808,6 +1846,14 @@ public final class ItemTypes { @Nullable public static final ItemType POLISHED_GRANITE_STAIRS = init(); @Nullable + public static final ItemType POLISHED_TUFF = init(); + @Nullable + public static final ItemType POLISHED_TUFF_SLAB = init(); + @Nullable + public static final ItemType POLISHED_TUFF_STAIRS = init(); + @Nullable + public static final ItemType POLISHED_TUFF_WALL = init(); + @Nullable public static final ItemType POPPED_CHORUS_FRUIT = init(); @Nullable public static final ItemType POPPY = init(); @@ -2061,6 +2107,8 @@ public final class ItemTypes { @Nullable public static final ItemType SHIELD = init(); @Nullable + public static final ItemType SHORT_GRASS = init(); + @Nullable public static final ItemType SHROOMLIGHT = init(); @Nullable public static final ItemType SHULKER_BOX = init(); @@ -2336,6 +2384,10 @@ public final class ItemTypes { @Nullable public static final ItemType TRAPPED_CHEST = init(); @Nullable + public static final ItemType TRIAL_KEY = init(); + @Nullable + public static final ItemType TRIAL_SPAWNER = init(); + @Nullable public static final ItemType TRIDENT = init(); @Nullable public static final ItemType TRIPWIRE_HOOK = init(); @@ -2354,6 +2406,20 @@ public final class ItemTypes { @Nullable public static final ItemType TUFF = init(); @Nullable + public static final ItemType TUFF_BRICK_SLAB = init(); + @Nullable + public static final ItemType TUFF_BRICK_STAIRS = init(); + @Nullable + public static final ItemType TUFF_BRICK_WALL = init(); + @Nullable + public static final ItemType TUFF_BRICKS = init(); + @Nullable + public static final ItemType TUFF_SLAB = init(); + @Nullable + public static final ItemType TUFF_STAIRS = init(); + @Nullable + public static final ItemType TUFF_WALL = init(); + @Nullable public static final ItemType TURTLE_EGG = init(); @Nullable public static final ItemType TURTLE_HELMET = init(); @@ -2418,32 +2484,72 @@ public final class ItemTypes { @Nullable public static final ItemType WATER_BUCKET = init(); @Nullable + public static final ItemType WAXED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_COPPER_BLOCK = init(); @Nullable + public static final ItemType WAXED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_EXPOSED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_EXPOSED_COPPER = init(); @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_EXPOSED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_EXPOSED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_OXIDIZED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_OXIDIZED_COPPER = init(); @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_OXIDIZED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_SLAB = init(); @Nullable public static final ItemType WAXED_OXIDIZED_CUT_COPPER_STAIRS = init(); @Nullable + public static final ItemType WAXED_WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WAXED_WEATHERED_COPPER = init(); @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_BULB = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WAXED_WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER = init(); @Nullable public static final ItemType WAXED_WEATHERED_CUT_COPPER_SLAB = init(); @@ -2452,8 +2558,18 @@ public final class ItemTypes { @Nullable public static final ItemType WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = init(); @Nullable + public static final ItemType WEATHERED_CHISELED_COPPER = init(); + @Nullable public static final ItemType WEATHERED_COPPER = init(); @Nullable + public static final ItemType WEATHERED_COPPER_BULB = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_DOOR = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_GRATE = init(); + @Nullable + public static final ItemType WEATHERED_COPPER_TRAPDOOR = init(); + @Nullable public static final ItemType WEATHERED_CUT_COPPER = init(); @Nullable public static final ItemType WEATHERED_CUT_COPPER_SLAB = init(); diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index f1d5d76df..bd77a7d6a 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -58,7 +58,8 @@ "fawe.worldedit.brush.brush.source.mask": "Brush source mask set", "fawe.worldedit.brush.brush.transform.disabled": "Brush transform disabled", "fawe.worldedit.brush.brush.transform": "Brush transform set", - "fawe.worldedit.rollback.rollback.element": "Undoing {0}", + "fawe.worldedit.rollback.rollingback.index": "Undoing {0} ...", + "fawe.worldedit.rollback.rollback.element": "{0} undone.", "fawe.worldedit.tool.tool.inspect": "Inspect tool bound to {0}.", "fawe.worldedit.tool.tool.inspect.info": "{0} changed {1} to {2} {3} ago", "fawe.worldedit.tool.tool.inspect.info.footer": "Total: {0} changes", @@ -95,6 +96,7 @@ "fawe.error.parser.invalid-data": "Invalid data: {0}", "fawe.error.unsupported": "Unsupported!", "fawe.error.invalid-block-type": "Does not match a valid block type: {0}", + "fawe.error.invalid-block-state-property": "Cannot parse value `{0}` for property `{1}`, block state: `{2}`", "fawe.error.nbt.forbidden": "You are not allowed to use nbt. Lacking permission: {0}", "fawe.error.invalid-arguments": "Invalid amount of arguments. Expected: {0}", "fawe.error.unrecognised-tag": "Unrecognised tag: {0} {1}", @@ -356,6 +358,7 @@ "worldedit.schematic.unknown-format": "Unknown schematic format: {0}.", "worldedit.schematic.load.does-not-exist": "Schematic {0} does not exist!", "worldedit.schematic.load.loading": "(Please wait... loading schematic.)", + "worldedit.schematic.load.unsupported-version": "This schematic is not supported. Version: {0}.", "worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.", "worldedit.schematic.save.failed-directory": "Could not create folder for schematics!", "worldedit.schematic.save.saving": "(Please wait... saving schematic.)", diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java index 3491347a4..3c8ba65d6 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java @@ -114,6 +114,11 @@ class BaseExpressionTest { public int getBlockDataRel(double x, double y, double z) { return (int) y * 100; } + + @Override + public ExpressionEnvironment clone() { + return this; + } }); return expression.evaluate(); diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts index f1aebbeba..6498cca7e 100644 --- a/worldedit-sponge/build.gradle.kts +++ b/worldedit-sponge/build.gradle.kts @@ -28,7 +28,7 @@ dependencies { }) api("org.apache.logging.log4j:log4j-api") api("org.bstats:bstats-sponge:1.7") - testImplementation("org.mockito:mockito-core:5.6.0") + testImplementation("org.mockito:mockito-core:5.11.0") } <<<<<<< HEAD