Merge remote-tracking branch 'upstream/main'

# Conflicts:
#	build.gradle.kts
#	settings.gradle.kts
#	worldedit-bukkit/build.gradle.kts
Dieser Commit ist enthalten in:
Chaoscaot 2024-11-27 23:59:14 +01:00
Commit 32e2ba6970
783 geänderte Dateien mit 30462 neuen und 15592 gelöschten Zeilen

Datei anzeigen

@ -342,7 +342,7 @@ ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true 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_attributes = true
ij_xml_align_text = false ij_xml_align_text = false
ij_xml_attribute_wrap = normal 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_space_inside_empty_tag = false
ij_xml_text_wrap = normal ij_xml_text_wrap = normal
[{*.ats, *.ts}] [{*.ats,*.ts}]
ij_continuation_indent_size = 4 ij_continuation_indent_size = 4
ij_typescript_align_imports = false ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = 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_while_on_new_line = false
ij_typescript_wrap_comments = false ij_typescript_wrap_comments = false
[{*.bash, *.sh, *.zsh}] [{*.bash,*.sh,*.zsh}]
indent_size = 2 indent_size = 2
tab_width = 2 tab_width = 2
ij_shell_binary_ops_start_line = false 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_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false ij_shell_switch_cases_indented = false
[{*.cjs, *.js}] [{*.cjs,*.js}]
ij_continuation_indent_size = 4 ij_continuation_indent_size = 4
ij_javascript_align_imports = false ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = 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_while_on_new_line = false
ij_javascript_wrap_comments = false ij_javascript_wrap_comments = false
[{*.ft, *.vm, *.vsl}] [{*.ft,*.vm,*.vsl}]
ij_vtl_keep_indents_on_empty_lines = false 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_group_field_declarations = false
ij_groovy_align_multiline_array_initializer_expression = false ij_groovy_align_multiline_array_initializer_expression = false
ij_groovy_align_multiline_assignment = 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_while_on_new_line = false
ij_groovy_wrap_long_lines = 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_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = 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_expression_body_functions = 0
ij_kotlin_wrap_first_method_in_call_chain = false 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 indent_size = 2
ij_json_keep_blank_lines_in_code = 0 ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false 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_spaces_within_brackets = false
ij_json_wrap_long_lines = 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_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true ij_html_align_attributes = true
ij_html_align_text = false ij_html_align_text = false
@ -1004,7 +1004,7 @@ ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal ij_html_text_wrap = normal
ij_html_uniform_ident = false ij_html_uniform_ident = false
[{*.yaml, *.yml}] [{*.yaml,*.yml}]
indent_size = 2 indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true ij_yaml_keep_line_breaks = true

Datei anzeigen

@ -27,11 +27,11 @@ 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. 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 multiple: false
options: options:
- '1.20.1' - '1.21.3'
- '1.20' - '1.21.1'
- '1.19.4' - '1.20.6'
- '1.18.2' - '1.20.4'
- '1.17.1' - '1.20.2'
validations: validations:
required: true required: true

46
.github/renovate.json vendored
Datei anzeigen

@ -1,11 +1,12 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema" : "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends" : [
"config:base", "config:recommended",
":semanticCommitsDisabled" ":semanticCommitsDisabled",
"schedule:earlyMondays"
], ],
"automerge": true, "automerge" : true,
"ignoreDeps": [ "ignoreDeps" : [
"guava", "guava",
"com.google.guava:guava", "com.google.guava:guava",
"rhino-runtime", "rhino-runtime",
@ -29,7 +30,34 @@
"org.spongepowered:spongeapi", "org.spongepowered:spongeapi",
"org.yaml:snakeyaml" "org.yaml:snakeyaml"
], ],
"labels": ["Renovate"], "labels" : [
"rebaseWhen": "conflicted", "Renovate"
"schedule": ["on the first day of the month"] ],
"rebaseWhen" : "conflicted",
"customManagers" : [
{
"customType" : "regex",
"datasourceTemplate" : "custom.paperweight-userdev",
"fileMatch" : "^worldedit-bukkit\\/adapters\\/adapter-\\d+_\\d+(_\\d+)?\\/build\\.gradle\\.kts$",
"matchStrings" : [
"url=(?<registryUrl>.*)\\s",
"paperDevBundle\\(\"(?<currentValue>.*?)\"\\)\\s"
],
"matchStringsStrategy": "combination",
"depNameTemplate" : "paperweight-userdev",
"extractVersionTemplate" : "(?<version>\\d+\\.\\d+\\.?\\d*-R0\\.1-\\d+\\.\\d+-\\d+)"
}
],
"customDatasources" : {
"paperweight-userdev": {
"defaultRegistryUrlTemplate": "",
"format": "html"
}
},
"packageRules" : [
{
"matchDatasources" : ["custom.paperweight-userdev"],
"versioning": "regex:^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)?-R0\\.1-\\d+\\d+\\.\\d+-(?<build>\\d+)$"
}
]
} }

Datei anzeigen

@ -24,5 +24,5 @@ jobs:
"" ""
"The download is available at:" "The download is available at:"
"- Spigot: <https://www.spigotmc.org/resources/13932/>" "- Spigot: <https://www.spigotmc.org/resources/13932/>"
"- Modrinth: <https://modrinth.com/plugin/fastasyncworldedit/version/${{ github.event.release.tag_name }}>" "- Modrinth: <https://modrinth.com/plugin/fastasyncworldedit>"
"- CurseForge: <https://www.curseforge.com/minecraft/bukkit-plugins/fawe>" "- CurseForge: <https://www.curseforge.com/minecraft/bukkit-plugins/fawe>"

Datei anzeigen

@ -9,19 +9,19 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest, macos-latest]
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/actions/wrapper-validation@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
cache: gradle cache: gradle
java-version: 17 java-version: 21
- name: Build on ${{ matrix.os }} - name: Build on ${{ matrix.os }}
run: ./gradlew build -s run: ./gradlew build -s
- name: Archive artifacts - name: Archive artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: FastAsyncWorldEdit-SNAPSHOT name: FastAsyncWorldEdit-SNAPSHOT
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar

Datei anzeigen

@ -9,15 +9,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/actions/wrapper-validation@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
cache: gradle cache: gradle
java-version: 17 java-version: 21
- name: Clean Build - name: Clean Build
run: ./gradlew clean build --no-daemon run: ./gradlew clean build --no-daemon
- name: Determine release status - name: Determine release status
@ -70,9 +70,9 @@ jobs:
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: FastAsyncWorldEdit-Bukkit-SNAPSHOT name: FastAsyncWorldEdit-Bukkit-SNAPSHOT
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar
- name: Publish to Modrinth - name: Publish to Modrinth
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}} if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
run: ./gradlew modrinth run: ./gradlew publishMods
env: env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}

Datei anzeigen

@ -19,18 +19,18 @@ jobs:
language: ['java'] language: ['java']
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
cache: gradle cache: gradle
java-version: 17 java-version: 21
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3

Datei anzeigen

@ -0,0 +1,23 @@
name: "Label conflicting PRs"
on:
push:
pull_request_target:
types: [ synchronize ]
pull_request:
types: [ synchronize ]
permissions:
pull-requests: write
jobs:
main:
if: github.event.pull_request.user.login != 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- name: Label conflicting PRs
uses: eps1lon/actions-label-merge-conflict@v3.0.2
with:
dirtyLabel: "unresolved-merge-conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "Please take a moment and address the merge conflicts of your pull request. Thanks!"
continueOnMissingPermissions: true

Datei anzeigen

@ -12,6 +12,6 @@ jobs:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@v5 - uses: release-drafter/release-drafter@v6
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Datei anzeigen

@ -7,20 +7,20 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/actions/wrapper-validation@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: temurin distribution: temurin
cache: gradle cache: gradle
java-version: 17 java-version: 21
- name: Clean Build - name: Clean Build
run: ./gradlew clean build --no-daemon run: ./gradlew clean build --no-daemon
- name: Upload Release Assets - name: Upload Release Assets
uses: AButler/upload-release-assets@v2.0 uses: AButler/upload-release-assets@v3.0
with: with:
files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar' files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-*.jar'
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
release-tag: ${{ github.event.release.tag_name }} release-tag: ${{ github.event.release.tag_name }}

Datei anzeigen

@ -3,12 +3,12 @@
= Compiling = Compiling
You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed, You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 21 installed. Gradle will download JDK 21 specifically if needed,
but it needs some version of Java to bootstrap from. but it needs some version of Java to bootstrap from.
Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 17. Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 21.
You can get the JDK 17 link:https://adoptium.net/[here] from Adoptium. You can get the JDK 21 link:https://adoptium.net/[here] from Adoptium.
The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules: The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules:

2
Jenkinsfile vendored
Datei anzeigen

@ -7,7 +7,7 @@ pipeline {
stage('Build') { stage('Build') {
steps { steps {
withEnv([ withEnv([
"PATH+JAVA=${tool 'Temurin-17.0.7_7'}/bin" "PATH+JAVA=${tool 'Temurin-21.0.3_9'}/bin"
]) { ]) {
sh './gradlew clean build' sh './gradlew clean build'
} }

Datei anzeigen

@ -6,8 +6,8 @@ import java.time.format.DateTimeFormatter
import xyz.jpenilla.runpaper.task.RunServer import xyz.jpenilla.runpaper.task.RunServer
plugins { plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.3.0" id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
id("xyz.jpenilla.run-paper") version "2.1.0" id("xyz.jpenilla.run-paper") version "2.3.1"
} }
if (!File("$rootDir/.git").exists()) { if (!File("$rootDir/.git").exists()) {
@ -34,7 +34,7 @@ logger.lifecycle("""
******************************************* *******************************************
""") """)
var rootVersion by extra("2.7.1") var rootVersion by extra("2.12.3")
var snapshot by extra("SNAPSHOT") var snapshot by extra("SNAPSHOT")
var revision: String by extra("") var revision: String by extra("")
var buildNumber by extra("") var buildNumber by extra("")
@ -83,7 +83,7 @@ allprojects {
} }
applyCommonConfiguration() applyCommonConfiguration()
val supportedVersions = listOf("1.16.5", "1.17", "1.17.1", "1.18.2", "1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20", "1.20.1") val supportedVersions = listOf("1.20.4", "1.20.5", "1.20.6", "1.21", "1.21.1", "1.21.3")
tasks { tasks {
supportedVersions.forEach { supportedVersions.forEach {
@ -91,13 +91,13 @@ tasks {
minecraftVersion(it) minecraftVersion(it)
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
.toTypedArray()) .toTypedArray())
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true") jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true", "--add-modules=jdk.incubator.vector")
group = "run paper" group = "run paper"
runDirectory.set(file("run-$it")) runDirectory.set(file("run-$it"))
} }
} }
runServer { runServer {
minecraftVersion("1.20.1") minecraftVersion("1.21.3")
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
.toTypedArray()) .toTypedArray())

Datei anzeigen

@ -22,13 +22,25 @@ val properties = Properties().also { props ->
dependencies { dependencies {
implementation(gradleApi()) implementation(gradleApi())
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.0") implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0")
implementation("com.github.johnrengelman:shadow:8.1.1") implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.5")
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.7.5")
constraints {
val asmVersion = "[9.7,)"
implementation("org.ow2.asm:asm:$asmVersion") {
because("Need Java 21 support in shadow")
}
implementation("org.ow2.asm:asm-commons:$asmVersion") {
because("Need Java 21 support in shadow")
}
implementation("org.vafer:jdependency:[2.10,)") {
because("Need Java 21 support in shadow")
}
}
} }
kotlin { kotlin {
jvmToolchain { jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(17)) (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(21))
} }
} }

Datei anzeigen

@ -20,4 +20,8 @@ fun Project.applyPaperweightAdapterConfiguration() {
tasks.named("assemble") { tasks.named("assemble") {
dependsOn("reobfJar") dependsOn("reobfJar")
} }
tasks.named("javadoc") {
enabled = false
}
} }

Datei anzeigen

@ -33,7 +33,7 @@ fun Project.applyCommonConfiguration() {
plugins.withId("java") { plugins.withId("java") {
the<JavaPluginExtension>().toolchain { the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(17)) languageVersion.set(JavaLanguageVersion.of(21))
} }
} }

Datei anzeigen

@ -21,17 +21,18 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
.matching { it.name == "compileJava" || it.name == "compileTestJava" } .matching { it.name == "compileJava" || it.name == "compileTestJava" }
.configureEach { .configureEach {
val disabledLint = listOf( val disabledLint = listOf(
"processing", "path", "fallthrough", "serial" "processing", "path", "fallthrough", "serial", "overloads", "this-escape",
) )
options.release.set(17) options.release.set(21)
options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" }) options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
options.isDeprecation = true options.isDeprecation = true
options.encoding = "UTF-8" options.encoding = "UTF-8"
options.compilerArgs.add("-parameters") options.compilerArgs.add("-parameters")
options.compilerArgs.add("--add-modules=jdk.incubator.vector")
} }
configurations.all { configurations.all {
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
} }
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {
@ -40,30 +41,30 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
dependencies { dependencies {
"compileOnly"("com.google.code.findbugs:jsr305:3.0.2") "compileOnly"("com.google.code.findbugs:jsr305:3.0.2")
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.10.0") "testImplementation"("org.junit.jupiter:junit-jupiter-api:5.11.1")
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.10.0") "testImplementation"("org.junit.jupiter:junit-jupiter-params:5.11.1")
"testImplementation"("org.mockito:mockito-core:5.4.0") "testImplementation"("org.mockito:mockito-core:5.14.0")
"testImplementation"("org.mockito:mockito-junit-jupiter:5.4.0") "testImplementation"("org.mockito:mockito-junit-jupiter:5.14.0")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.10.0") "testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.11.1")
} }
// Java 8 turns on doclint which we fail // Java 8 turns on doclint which we fail
tasks.withType<Javadoc>().configureEach { tasks.withType<Javadoc>().configureEach {
(options as StandardJavadocDocletOptions).apply { (options as StandardJavadocDocletOptions).apply {
addStringOption("Xdoclint:none", "-quiet") addStringOption("Xdoclint:none", "-quiet")
addStringOption("-add-modules", "jdk.incubator.vector")
tags( tags(
"apiNote:a:API Note:", "apiNote:a:API Note:",
"implSpec:a:Implementation Requirements:", "implSpec:a:Implementation Requirements:",
"implNote:a:Implementation Note:" "implNote:a:Implementation Note:"
) )
options.encoding = "UTF-8" options.encoding = "UTF-8"
links( links(
"https://jd.advntr.dev/api/latest/", "https://jd.advntr.dev/api/latest/",
"https://logging.apache.org/log4j/2.x/log4j-api/apidocs/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
"https://www.antlr.org/api/Java/", "https://www.antlr.org/api/Java/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/", "https://jd.papermc.io/paper/1.21.1/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/",
"https://jd.papermc.io/paper/1.20/",
"https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/"
) )
docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}" docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}"

Datei anzeigen

@ -29,7 +29,7 @@ fun Project.applyLibrariesConfiguration() {
applyCommonConfiguration() applyCommonConfiguration()
apply(plugin = "java-base") apply(plugin = "java-base")
apply(plugin = "maven-publish") apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.gradleup.shadow")
apply(plugin = "signing") apply(plugin = "signing")
configurations { configurations {
@ -40,8 +40,7 @@ fun Project.applyLibrariesConfiguration() {
val relocations = mapOf( val relocations = mapOf(
"net.kyori.text" to "com.sk89q.worldedit.util.formatting.text", "net.kyori.text" to "com.sk89q.worldedit.util.formatting.text",
"net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori", "net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori"
"net.kyori.adventure.nbt" to "com.sk89q.worldedit.util.nbt"
) )
@ -53,9 +52,14 @@ fun Project.applyLibrariesConfiguration() {
exclude(dependency("com.google.guava:guava")) exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson")) exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("com.google.errorprone:error_prone_annotations")) exclude(dependency("com.google.errorprone:error_prone_annotations"))
exclude(dependency("com.google.guava:failureaccess"))
exclude(dependency("org.checkerframework:checker-qual")) exclude(dependency("org.checkerframework:checker-qual"))
exclude(dependency("org.jetbrains:annotations"))
exclude(dependency("org.apache.logging.log4j:log4j-api")) exclude(dependency("org.apache.logging.log4j:log4j-api"))
exclude(dependency("com.google.code.findbugs:jsr305")) exclude(dependency("com.google.code.findbugs:jsr305"))
exclude {
it.moduleGroup == "org.jetbrains.kotlin"
}
} }
relocations.forEach { (from, to) -> relocations.forEach { (from, to) ->
@ -67,12 +71,20 @@ fun Project.applyLibrariesConfiguration() {
.filterIsInstance<ModuleDependency>() .filterIsInstance<ModuleDependency>()
.map { it.copy() } .map { it.copy() }
.map { dependency -> .map { dependency ->
val category = dependency.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name
if (category == Category.REGULAR_PLATFORM || category == Category.ENFORCED_PLATFORM) {
return@map dependency
}
try {
dependency.artifact { dependency.artifact {
name = dependency.name name = dependency.name
type = artifactType type = artifactType
extension = "jar" extension = "jar"
classifier = artifactType classifier = artifactType
} }
} catch (e: Exception) {
throw RuntimeException("Failed to add artifact to dependency: $dependency", e)
}
dependency dependency
} }
@ -85,6 +97,10 @@ fun Project.applyLibrariesConfiguration() {
from({ from({
altConfigFiles("sources") altConfigFiles("sources")
}) })
// Yeet module-info's
exclude("module-info.java")
relocations.forEach { (from, to) -> relocations.forEach { (from, to) ->
val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)") val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)")
val textPattern = Regex.fromLiteral(from) val textPattern = Regex.fromLiteral(from)
@ -122,7 +138,7 @@ fun Project.applyLibrariesConfiguration() {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
} }
outgoing.artifact(tasks.named("jar")) outgoing.artifact(tasks.named("jar"))
} }
@ -137,7 +153,7 @@ fun Project.applyLibrariesConfiguration() {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY)) attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED)) attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR)) attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
} }
outgoing.artifact(tasks.named("jar")) outgoing.artifact(tasks.named("jar"))
} }
@ -241,8 +257,9 @@ fun Project.applyLibrariesConfiguration() {
scm { scm {
url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit") url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit")
connection.set("scm:https://IntellectualSites@github.com/IntellectualSites/FastAsyncWorldEdit.git") connection.set("scm:git:https://github.com/IntellectualSites/FastAsyncWorldEdit.git")
developerConnection.set("scm:git://github.com/IntellectualSites/FastAsyncWorldEdit.git") developerConnection.set("scm:git:git@github.com:IntellectualSites/FastAsyncWorldEdit.git")
tag.set("${project.version}")
} }
issueManagement { issueManagement {

Datei anzeigen

@ -12,6 +12,7 @@ import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the import org.gradle.kotlin.dsl.the
import org.gradle.kotlin.dsl.withType
import org.gradle.plugins.signing.SigningExtension import org.gradle.plugins.signing.SigningExtension
fun Project.applyPlatformAndCoreConfiguration() { fun Project.applyPlatformAndCoreConfiguration() {
@ -20,7 +21,7 @@ fun Project.applyPlatformAndCoreConfiguration() {
apply(plugin = "eclipse") apply(plugin = "eclipse")
apply(plugin = "idea") apply(plugin = "idea")
apply(plugin = "maven-publish") apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.gradleup.shadow")
apply(plugin = "signing") apply(plugin = "signing")
applyCommonJavaConfiguration( applyCommonJavaConfiguration(
@ -87,23 +88,27 @@ fun Project.applyPlatformAndCoreConfiguration() {
name.set("Alexander Brandes") name.set("Alexander Brandes")
email.set("contact(at)notmyfault.dev") email.set("contact(at)notmyfault.dev")
organization.set("IntellectualSites") organization.set("IntellectualSites")
organizationUrl.set("https://github.com/IntellectualSites")
} }
developer { developer {
id.set("SirYwell") id.set("SirYwell")
name.set("Hannes Greule") name.set("Hannes Greule")
organization.set("IntellectualSites") organization.set("IntellectualSites")
organizationUrl.set("https://github.com/IntellectualSites")
} }
developer { developer {
id.set("dordsor21") id.set("dordsor21")
name.set("dordsor21") name.set("dordsor21")
organization.set("IntellectualSites") organization.set("IntellectualSites")
organizationUrl.set("https://github.com/IntellectualSites")
} }
} }
scm { scm {
url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit") url.set("https://github.com/IntellectualSites/FastAsyncWorldEdit")
connection.set("scm:https://IntellectualSites@github.com/IntellectualSites/FastAsyncWorldEdit.git") connection.set("scm:git:https://github.com/IntellectualSites/FastAsyncWorldEdit.git")
developerConnection.set("scm:git://github.com/IntellectualSites/FastAsyncWorldEdit.git") developerConnection.set("scm:git:git@github.com:IntellectualSites/FastAsyncWorldEdit.git")
tag.set("${project.version}")
} }
issueManagement{ issueManagement{
@ -128,7 +133,8 @@ fun Project.applyPlatformAndCoreConfiguration() {
} }
fun Project.applyShadowConfiguration() { fun Project.applyShadowConfiguration() {
tasks.named<ShadowJar>("shadowJar") { tasks.withType<ShadowJar>().configureEach {
relocate("com.sk89q.jchronic", "com.sk89q.worldedit.jchronic")
dependencies { dependencies {
include(project(":worldedit-libs:core")) include(project(":worldedit-libs:core"))
include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}"))

Datei anzeigen

@ -1,6 +1,6 @@
[versions] [versions]
# Minecraft expectations # Minecraft expectations
paper = "1.20.1-R0.1-SNAPSHOT" paper = "1.21-R0.1-SNAPSHOT"
fastutil = "8.5.9" fastutil = "8.5.9"
guava = "31.1-jre" guava = "31.1-jre"
log4j = "2.19.0" log4j = "2.19.0"
@ -9,48 +9,49 @@ snakeyaml = "2.0"
# Plugins # Plugins
dummypermscompat = "1.10" dummypermscompat = "1.10"
worldguard-bukkit = "7.0.9" worldguard-bukkit = "7.0.12"
mapmanager = "1.8.0-SNAPSHOT" mapmanager = "1.8.0-SNAPSHOT"
griefprevention = "16.18.1" griefprevention = "17.0.0"
griefdefender = "2.1.0-SNAPSHOT" griefdefender = "2.1.0-SNAPSHOT"
residence = "4.5._13.1" residence = "4.5._13.1"
towny = "0.99.5.10" towny = "0.100.4.13"
plotsquared = "7.0.0-rc.4" plotsquared = "7.4.0"
# Third party # Third party
bstats = "3.0.2" bstats = "3.1.0"
sparsebitset = "1.2" sparsebitset = "1.3"
parallelgzip = "1.0.5" parallelgzip = "1.0.5"
adventure = "4.14.0" adventure = "4.17.0"
adventure-bukkit = "4.3.0" adventure-bukkit = "4.3.4"
checkerqual = "3.37.0" checkerqual = "3.48.2"
truezip = "6.8.4" truezip = "6.8.4"
auto-value = "1.10.2" auto-value = "1.11.0"
findbugs = "3.0.2" findbugs = "3.0.2"
rhino-runtime = "1.7.14" rhino-runtime = "1.7.15"
zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs
antlr4 = "4.13.0" antlr4 = "4.13.2"
json-simple = "1.1.1" json-simple = "1.1.1"
jlibnoise = "1.0.0" jlibnoise = "1.0.0"
jchronic = "0.2.4a" jchronic = "0.2.4a"
lz4-java = "1.8.0" lz4-java = "1.8.0"
lz4-stream = "1.0.0" lz4-stream = "1.0.0"
commons-cli = "1.5.0" commons-cli = "1.9.0"
paperlib = "1.0.8" paperlib = "1.0.8"
paster = "1.1.5" paster = "1.1.6"
vault = "1.7.1" vault = "1.7.1"
serverlib = "2.3.1" serverlib = "2.3.6"
linbus = "0.2.0"
## Internal ## Internal
text-adapter = "3.0.6" text-adapter = "3.0.6"
text = "3.0.4" text = "3.0.4"
piston = "0.5.7" piston = "0.5.10"
# Tests # Tests
mockito = "5.4.0" mockito = "5.14.2"
# Gradle plugins # Gradle plugins
pluginyml = "0.6.0" pluginyml = "0.6.0"
minotaur = "2.8.3" mod-publish-plugin = "0.8.1"
[libraries] [libraries]
# Minecraft expectations # Minecraft expectations
@ -78,7 +79,6 @@ bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats
bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" } bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" } sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" }
parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" } parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" }
adventureNbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" }
truezip = { group = "de.schlichtherle", name = "truezip", version.ref = "truezip" } truezip = { group = "de.schlichtherle", name = "truezip", version.ref = "truezip" }
autoValueAnnotations = { group = "com.google.auto.value", name = "auto-value-annotations", version.ref = "auto-value" } autoValueAnnotations = { group = "com.google.auto.value", name = "auto-value-annotations", version.ref = "auto-value" }
autoValue = { group = "com.google.auto.value", name = "auto-value", version.ref = "auto-value" } autoValue = { group = "com.google.auto.value", name = "auto-value", version.ref = "auto-value" }
@ -101,6 +101,11 @@ paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" } vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" } serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" } checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" }
linBus-bom = { group = "org.enginehub.lin-bus", name = "lin-bus-bom", version.ref = "linbus" }
linBus-common = { group = "org.enginehub.lin-bus", name = "lin-bus-common" }
linBus-stream = { group = "org.enginehub.lin-bus", name = "lin-bus-stream" }
linBus-tree = { group = "org.enginehub.lin-bus", name = "lin-bus-tree" }
linBus-format-snbt = { group = "org.enginehub.lin-bus.format", name = "lin-bus-format-snbt" }
# Internal # Internal
## Text ## Text
@ -122,4 +127,4 @@ log4jCore = { group = "org.apache.logging.log4j", name = "log4j-core", version.r
[plugins] [plugins]
pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" } pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" } mod-publish-plugin = { id = "me.modmuss50.mod-publish-plugin", version.ref = "mod-publish-plugin" }

Binäre Datei nicht angezeigt.

Datei anzeigen

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

22
gradlew vendored
Datei anzeigen

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -83,7 +85,9 @@ done
# This is normally unused # This is normally unused
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045 # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -201,11 +205,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command:
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# shell script including quotes and variable substitutions, so put them in # and any embedded shellness will be escaped.
# double quotes to make sure that they get re-expanded; and # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * put everything else in single quotes, so that it's not re-expanded. # treated as '${Hostname}' itself on the command line.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \

22
gradlew.bat vendored
Datei anzeigen

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail

Datei anzeigen

@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit"
include("worldedit-libs") include("worldedit-libs")
listOf("legacy", "1_17_1", "1_18_2", "1_19", "1_19_3","1_19_4", "1_20").forEach { listOf("1_20_2", "1_20_4", "1_20_5", "1_21", "1_21_3").forEach {
include("worldedit-bukkit:adapters:adapter-$it") include("worldedit-bukkit:adapters:adapter-$it")
} }

Datei anzeigen

@ -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<ClientboundLevelChunkPacket> {
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();
}
}

Datei anzeigen

@ -1,511 +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.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 int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldLock;
private static final long fieldLockOffset;
private static final Field fieldGameEventDispatcherSections;
private static final MethodHandle methodremoveBlockEntityTicker;
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);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) {
fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
} else {
// in paper, the used methods are synchronized properly
fieldLock = null;
fieldLockOffset = -1;
}
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);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (RuntimeException e) {
throw e;
} catch (Throwable rethrow) {
rethrow.printStackTrace();
throw new RuntimeException(rethrow);
}
}
static boolean setSectionAtomic(
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
}
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> 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) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
Semaphore currentLock = (Semaphore) unsafe.getObject(blocks, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore;
}
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(blocks, fieldLockOffset, newLock);
return newLock;
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
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<org.bukkit.Chunk> 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<LevelChunk> 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<ServerPlayer> 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<Integer, char[]> 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<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks =
levelChunkSection.getStates();
// private DataPalette<T> h;
// protected DataBits a;
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
final BitStorage nmsBits = new BitStorage(bitsPerEntry, 4096, bits);
final Palette<net.minecraft.world.level.block.state.BlockState> 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<GameEventDispatcher>) 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<Entity> getEntities(LevelChunk chunk) {
return chunk.level.entityManager.getEntities(chunk.getPos());
}
}

Datei anzeigen

@ -1,239 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.TaskManager;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.MCUtil;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter implements Relighter {
public static final MethodHandle RELIGHT;
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32
private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT);
static {
MethodHandle tmp = null;
try {
MethodHandles.Lookup lookup = MethodHandles.lookup();
tmp = lookup.findVirtual(
ThreadedLevelLightEngine.class,
"relight",
MethodType.methodType(
int.class, // return type
// params
Set.class,
Consumer.class,
IntConsumer.class
)
);
} catch (NoSuchMethodException | IllegalAccessException e) {
LOGGER.error("Failed to locate 'relight' method in ThreadedLevelLightEngine. Is everything up to date?", e);
}
RELIGHT = tmp;
}
private final ServerLevel serverLevel;
private final ReentrantLock lock = new ReentrantLock();
private final Long2ObjectLinkedOpenHashMap<LongSet> regions = new Long2ObjectLinkedOpenHashMap<>();
private final ReentrantLock areaLock = new ReentrantLock();
private final NMSRelighter delegate;
@SuppressWarnings("rawtypes")
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) {
this.serverLevel = serverLevel;
this.delegate = new NMSRelighter(queue);
}
public static boolean isUsable() {
return RELIGHT != null;
}
@Override
public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) {
areaLock.lock();
try {
long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2);
// TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH?
LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2));
chunks.add(ChunkPos.asLong(cx, cz));
} finally {
areaLock.unlock();
}
return true;
}
@Override
public void addLightUpdate(int x, int y, int z) {
delegate.addLightUpdate(x, y, z);
}
/*
* This method is called "recursively", iterating and removing elements
* from the regions linked map. This way, chunks are loaded in batches to avoid
* OOMEs.
*/
@Override
public void fixLightingSafe(boolean sky) {
this.areaLock.lock();
try {
if (regions.isEmpty()) {
return;
}
LongSet first = regions.removeFirst();
fixLighting(first, () -> fixLightingSafe(true));
} finally {
this.areaLock.unlock();
}
}
/*
* Processes a set of chunks and runs an action afterwards.
* The action is run async, the chunks are partly processed on the main thread
* (as required by the server).
*/
private void fixLighting(LongSet chunks, Runnable andThen) {
// convert from long keys to ChunkPos
Set<ChunkPos> coords = new HashSet<>();
LongIterator iterator = chunks.iterator();
while (iterator.hasNext()) {
coords.add(new ChunkPos(iterator.nextLong()));
}
TaskManager.taskManager().task(() -> {
// trigger chunk load and apply ticket on main thread
List<CompletableFuture<?>> futures = new ArrayList<>();
for (ChunkPos pos : coords) {
futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
pos,
LIGHT_LEVEL,
Unit.INSTANCE
))
);
}
// collect futures and trigger relight once all chunks are loaded
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v ->
invokeRelight(
coords,
c -> {
}, // no callback for single chunks required
i -> {
if (i != coords.size()) {
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
}
// post process chunks on main thread
TaskManager.taskManager().task(() -> postProcessChunks(coords));
// call callback on our own threads
TaskManager.taskManager().async(andThen);
}
)
);
});
}
private void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
int unused = (int) RELIGHT.invokeExact(
serverLevel.getChunkSource().getLightEngine(),
coords,
chunkCallback, // callback per chunk
processCallback // callback for all chunks
);
} catch (Throwable throwable) {
LOGGER.error("Error occurred on relighting", throwable);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
private void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
@Override
public void clear() {
}
@Override
public void removeLighting() {
this.delegate.removeLighting();
}
@Override
public void fixBlockLighting() {
fixLightingSafe(true);
}
@Override
public void fixSkyLighting() {
fixLightingSafe(true);
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public ReentrantLock getLock() {
return this.lock;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public void close() throws Exception {
fixLightingSafe(true);
}
}

Datei anzeigen

@ -1,697 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.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.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.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 net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.data.worldgen.biome.Biomes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.LinearCongruentialGenerator;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.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.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.SimpleRandomSource;
import net.minecraft.world.level.levelgen.WorldGenSettings;
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.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.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;
import java.util.List;
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;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field worldsField;
private static final Field paperConfigField;
private static final Field generateFlatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
//list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.FULL
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(
ChunkStatus.LIQUID_CARVERS,
Concurrency.NONE
); // liquid carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
worldsField = CraftServer.class.getDeclaredField("worlds");
worldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
generateFlatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "g"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "e"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C"));
chunkSourceField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureManager structureManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
if (!(originalChunkProvider instanceof ServerChunkCache)) {
return false;
}
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = generateFlatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
BiomeProvider biomeProvider = getBiomeProvider();
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldGenSettings originalOpts = originalWorldData.worldGenSettings();
WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataPackConfig()
);
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable());
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
originalServerWorld.dimensionType(),
new RegenNoOpWorldLoadListener(),
// placeholder. Required for new ChunkProviderServer, but we create and then set it later
newOpts.dimensions().get(levelStemResourceKey).generator(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
environment,
generator,
biomeProvider
) {
private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(
options
.getBiomeType()
.getId())) : null;
@Override
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
}
@Override
public Biome getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ);
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig);
}
//generator
if (originalChunkProvider.getGenerator() instanceof FlatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = (FlatLevelGeneratorSettings) generatorSettingFlatField.get(
originalChunkProvider.getGenerator());
chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator) {
Supplier<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Supplier<NoiseGeneratorSettings>) generatorSettingBaseSupplierField
.get(originalChunkProvider.getGenerator());
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options
.getBiomeType()
.getId())));
} else {
biomeSource = originalChunkProvider.getGenerator().getBiomeSource();
if (biomeSource instanceof OverworldBiomeSource) {
biomeSource = fastOverworldBiomeSource(biomeSource);
}
}
chunkGenerator = new NoiseBasedChunkGenerator(biomeSource, seed, generatorSettingBaseSupplier);
} else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator) {
chunkGenerator = (ChunkGenerator) delegateField.get(originalChunkProvider.getGenerator());
} else {
LOGGER.error("Unsupported generator type {}", originalChunkProvider.getGenerator().getClass().getName());
return false;
}
if (generator != null) {
chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator);
generateConcurrent = generator.isParallelCapable();
}
freshChunkProvider = new ServerChunkCache(
freshWorld,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureManager = server.getStructureManager();
threadedLevelLightEngine = freshChunkProvider.getLightEngine();
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return PaperLib.isPaper()
? new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, freshWorld) // paper
: new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld); // spigot
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk()));
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) worldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
@SuppressWarnings({"unchecked", "rawtypes"})
private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception {
Field legacyBiomeInitLayerField = OverworldBiomeSource.class.getDeclaredField(
Refraction.pickName("legacyBiomeInitLayer", "i"));
legacyBiomeInitLayerField.setAccessible(true);
Field largeBiomesField = OverworldBiomeSource.class.getDeclaredField(Refraction.pickName("largeBiomes", "j"));
largeBiomesField.setAccessible(true);
Field biomeRegistryField = OverworldBiomeSource.class.getDeclaredField(Refraction.pickName("biomes", "k"));
biomeRegistryField.setAccessible(true);
Field areaLazyField = Layer.class.getDeclaredField(Refraction.pickName("area", "b"));
areaLazyField.setAccessible(true);
Method initAreaFactoryMethod = Layers.class.getDeclaredMethod(
Refraction.pickName("getDefaultLayer", "a"),
boolean.class,
int.class,
int.class,
LongFunction.class
);
initAreaFactoryMethod.setAccessible(true);
//init new WorldChunkManagerOverworld
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(biomeSource);
boolean largebiomes = largeBiomesField.getBoolean(biomeSource);
Registry<Biome> biomeRegistryMojang = (Registry<Biome>) biomeRegistryField.get(biomeSource);
Registry<Biome> 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<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) 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<Biome> biomeRegistry;
private final boolean isSingleRegistry;
private final FastGenLayer fastGenLayer;
public FastOverworldBiomeSource(
Registry<Biome> biomeRegistry,
FastGenLayer genLayer
) {
super(biomeRegistry.stream().collect(Collectors.toList()));
this.biomeRegistry = biomeRegistry;
this.isSingleRegistry = biomeRegistry.entrySet().size() == 1;
this.fastGenLayer = genLayer;
}
@Override
protected Codec<? extends BiomeSource> 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<FastAreaLazy> {
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
private final ImprovedNoise improvedNoise;
private final long magicrandom;
private final ConcurrentHashMap<Long, Long> 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<FastAreaLazy> factory) {
super(() -> null);
this.fastAreaLazy = factory.make();
}
@Override
public Biome get(Registry<Biome> registry, int x, int z) {
ResourceKey<Biome> 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<Long, Integer> 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() {
}
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
// avoid warning on paper
public FastProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world, ServerLevel serverLevel) {
super(pos, upgradeData, world, serverLevel);
}
// compatibility with spigot
public FastProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor) {
super(pos, upgradeData, levelHeightAccessor);
}
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return chunkStatus.getRange();
}
@Override
public String name() {
return chunkStatus.getName();
}
@Override
public CompletableFuture<?> processChunk(Long xz, List<ChunkAccess> accessibleChunks) {
return chunkStatus.generate(
Runnable::run, // TODO revisit, we might profit from this somehow?
freshWorld,
chunkGenerator,
structureManager,
threadedLevelLightEngine,
c -> CompletableFuture.completedFuture(Either.left(c)),
accessibleChunks
);
}
}
}

Datei anzeigen

@ -1,541 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen;
import com.fastasyncworldedit.bukkit.adapter.Regenerator;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.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 it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.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.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field flatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
private static final Field ringPositionsField;
private static final Field hasGeneratedPositionsField;
//list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.FULL
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(
ChunkStatus.LIQUID_CARVERS,
Concurrency.NONE
); // liquid carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "h"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "g"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "K"));
chunkSourceField.setAccessible(true);
ringPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("ringPositions", "h"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("hasGeneratedPositions", "i"));
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureManager structureManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
if (!(originalChunkProvider instanceof ServerChunkCache)) {
return false;
}
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
BiomeProvider biomeProvider = getBiomeProvider();
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldGenSettings originalOpts = originalWorldData.worldGenSettings();
WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataPackConfig()
);
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable());
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
originalServerWorld.dimensionTypeRegistration(),
new RegenNoOpWorldLoadListener(),
// placeholder. Required for new ChunkProviderServer, but we create and then set it later
newOpts.dimensions().getOrThrow(levelStemResourceKey).generator(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.asHolderIdMap().byId(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
}
@Override
public Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ,
PaperweightRegen.this.chunkGenerator.climateSampler()
);
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig);
}
//generator
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator();
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(originalGenerator.structureSets, generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier =
(Holder<NoiseGeneratorSettings>) generatorSettingBaseSupplierField
.get(originalGenerator);
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME
.asHolderIdMap()
.byId(WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())));
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(originalGenerator.structureSets, noiseBasedChunkGenerator.noises,
biomeSource, seed,
generatorSettingBaseSupplier
);
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.delegate;
} else {
LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName());
return false;
}
if (generator != null) {
chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator);
generateConcurrent = generator.isParallelCapable();
}
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(originalGenerator);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> ringPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(
originalGenerator);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(ringPositions);
ringPositionsField.set(chunkGenerator, copy);
hasGeneratedPositionsField.setBoolean(chunkGenerator, true);
}
}
chunkGenerator.conf = originalServerWorld.spigotConfig;
freshChunkProvider = new ServerChunkCache(
freshWorld,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
freshWorld.spigotConfig.simulationDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureManager = server.getStructureManager();
threadedLevelLightEngine = freshChunkProvider.getLightEngine();
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld,
this.freshWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null
);
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk()));
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
public FastProtoChunk(
final ChunkPos pos,
final UpgradeData upgradeData,
final LevelHeightAccessor world,
final Registry<Biome> biomeRegistry,
@Nullable final BlendingData blendingData
) {
super(pos, upgradeData, world, biomeRegistry, blendingData);
}
// avoid warning on paper
// compatibility with spigot
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return chunkStatus.getRange();
}
@Override
public String name() {
return chunkStatus.getName();
}
@Override
public CompletableFuture<?> processChunk(Long xz, List<ChunkAccess> accessibleChunks) {
return chunkStatus.generate(
Runnable::run, // TODO revisit, we might profit from this somehow?
freshWorld,
chunkGenerator,
structureManager,
threadedLevelLightEngine,
c -> CompletableFuture.completedFuture(Either.left(c)),
accessibleChunks,
true
);
}
}
}

Datei anzeigen

@ -1,205 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.TaskManager;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter implements Relighter {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32
private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT);
private final ServerLevel serverLevel;
private final ReentrantLock lock = new ReentrantLock();
private final Long2ObjectLinkedOpenHashMap<LongSet> regions = new Long2ObjectLinkedOpenHashMap<>();
private final ReentrantLock areaLock = new ReentrantLock();
private final NMSRelighter delegate;
@SuppressWarnings("rawtypes")
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) {
this.serverLevel = serverLevel;
this.delegate = new NMSRelighter(queue);
}
@Override
public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) {
areaLock.lock();
try {
long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2);
// TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH?
LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2));
chunks.add(ChunkPos.asLong(cx, cz));
} finally {
areaLock.unlock();
}
return true;
}
@Override
public void addLightUpdate(int x, int y, int z) {
delegate.addLightUpdate(x, y, z);
}
/*
* This method is called "recursively", iterating and removing elements
* from the regions linked map. This way, chunks are loaded in batches to avoid
* OOMEs.
*/
@Override
public void fixLightingSafe(boolean sky) {
this.areaLock.lock();
try {
if (regions.isEmpty()) {
return;
}
LongSet first = regions.removeFirst();
fixLighting(first, () -> fixLightingSafe(true));
} finally {
this.areaLock.unlock();
}
}
/*
* Processes a set of chunks and runs an action afterwards.
* The action is run async, the chunks are partly processed on the main thread
* (as required by the server).
*/
private void fixLighting(LongSet chunks, Runnable andThen) {
// convert from long keys to ChunkPos
Set<ChunkPos> coords = new HashSet<>();
LongIterator iterator = chunks.iterator();
while (iterator.hasNext()) {
coords.add(new ChunkPos(iterator.nextLong()));
}
TaskManager.taskManager().task(() -> {
// trigger chunk load and apply ticket on main thread
List<CompletableFuture<?>> futures = new ArrayList<>();
for (ChunkPos pos : coords) {
futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
pos,
LIGHT_LEVEL,
Unit.INSTANCE
))
);
}
// collect futures and trigger relight once all chunks are loaded
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v ->
invokeRelight(
coords,
c -> {
}, // no callback for single chunks required
i -> {
if (i != coords.size()) {
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
}
// post process chunks on main thread
TaskManager.taskManager().task(() -> postProcessChunks(coords));
// call callback on our own threads
TaskManager.taskManager().async(andThen);
}
)
);
});
}
private void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
private void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
@Override
public void clear() {
}
@Override
public void removeLighting() {
this.delegate.removeLighting();
}
@Override
public void fixBlockLighting() {
fixLightingSafe(true);
}
@Override
public void fixSkyLighting() {
fixLightingSafe(true);
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public ReentrantLock getLock() {
return this.lock;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public void close() throws Exception {
fixLightingSafe(true);
}
}

Datei anzeigen

@ -1,599 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_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.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_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 it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
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.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;
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.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;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
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.Chunk;
import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field flatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
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<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.FULL
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(
ChunkStatus.LIQUID_CARVERS,
Concurrency.NONE
); // liquid carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "M"));
chunkSourceField.setAccessible(true);
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w"));
generatorStructureStateField.setAccessible(true);
ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(
Refraction.pickName("hasGeneratedPositions", "h")
);
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureTemplateManager structureTemplateManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
if (!(originalChunkProvider instanceof ServerChunkCache)) {
return false;
}
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
.getOrThrow(levelStemResourceKey),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
environment,
generator,
biomeProvider
) {
private final Holder<Biome> 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 Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
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());
}
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator();
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Holder<NoiseGeneratorSettings>) generatorSettingBaseSupplierField.get(
originalGenerator);
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(
DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
)
);
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(
biomeSource,
generatorSettingBaseSupplier
);
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.getDelegate();
} else {
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,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
freshWorld.spigotConfig.simulationDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap);
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> origPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(state);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(
origPositions);
ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap);
ringPositionsField.set(newState, copy);
hasGeneratedPositionsField.setBoolean(newState, true);
}
}
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureTemplateManager = server.getStructureManager();
threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider);
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld,
this.freshWorld.registryAccess().registryOrThrow(BIOME), null
);
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> {
final CraftWorld world = freshWorld.getWorld();
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
blockPopulator.populate(world, random, chunk);
});
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
public FastProtoChunk(
final ChunkPos pos,
final UpgradeData upgradeData,
final LevelHeightAccessor world,
final Registry<Biome> biomeRegistry,
@Nullable final BlendingData blendingData
) {
super(pos, upgradeData, world, biomeRegistry, blendingData);
}
// avoid warning on paper
// compatibility with spigot
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return chunkStatus.getRange();
}
@Override
public String name() {
return chunkStatus.getName();
}
@Override
public CompletableFuture<?> processChunk(Long xz, List<ChunkAccess> accessibleChunks) {
return chunkStatus.generate(
Runnable::run, // TODO revisit, we might profit from this somehow?
freshWorld,
chunkGenerator,
structureTemplateManager,
threadedLevelLightEngine,
c -> CompletableFuture.completedFuture(Either.left(c)),
accessibleChunks,
true
);
}
}
/**
* A light engine that does nothing. As light is calculated after pasting anyway, we can avoid
* work this way.
*/
static class NoOpLightEngine extends ThreadedLevelLightEngine {
private static final ProcessorMailbox<Runnable> MAILBOX = ProcessorMailbox.create(task -> {
}, "fawe-no-op");
private static final ProcessorHandle<Message<Runnable>> HANDLE = ProcessorHandle.of("fawe-no-op", m -> {
});
public NoOpLightEngine(final ServerChunkCache chunkProvider) {
super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE);
}
@Override
public CompletableFuture<ChunkAccess> retainData(final ChunkAccess chunk) {
return CompletableFuture.completedFuture(chunk);
}
@Override
public CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) {
return CompletableFuture.completedFuture(chunk);
}
}
}

Datei anzeigen

@ -1,205 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.TaskManager;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter implements Relighter {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32
private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT);
private final ServerLevel serverLevel;
private final ReentrantLock lock = new ReentrantLock();
private final Long2ObjectLinkedOpenHashMap<LongSet> regions = new Long2ObjectLinkedOpenHashMap<>();
private final ReentrantLock areaLock = new ReentrantLock();
private final NMSRelighter delegate;
@SuppressWarnings("rawtypes")
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) {
this.serverLevel = serverLevel;
this.delegate = new NMSRelighter(queue);
}
@Override
public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) {
areaLock.lock();
try {
long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2);
// TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH?
LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2));
chunks.add(ChunkPos.asLong(cx, cz));
} finally {
areaLock.unlock();
}
return true;
}
@Override
public void addLightUpdate(int x, int y, int z) {
delegate.addLightUpdate(x, y, z);
}
/*
* This method is called "recursively", iterating and removing elements
* from the regions linked map. This way, chunks are loaded in batches to avoid
* OOMEs.
*/
@Override
public void fixLightingSafe(boolean sky) {
this.areaLock.lock();
try {
if (regions.isEmpty()) {
return;
}
LongSet first = regions.removeFirst();
fixLighting(first, () -> fixLightingSafe(true));
} finally {
this.areaLock.unlock();
}
}
/*
* Processes a set of chunks and runs an action afterwards.
* The action is run async, the chunks are partly processed on the main thread
* (as required by the server).
*/
private void fixLighting(LongSet chunks, Runnable andThen) {
// convert from long keys to ChunkPos
Set<ChunkPos> coords = new HashSet<>();
LongIterator iterator = chunks.iterator();
while (iterator.hasNext()) {
coords.add(new ChunkPos(iterator.nextLong()));
}
TaskManager.taskManager().task(() -> {
// trigger chunk load and apply ticket on main thread
List<CompletableFuture<?>> futures = new ArrayList<>();
for (ChunkPos pos : coords) {
futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
pos,
LIGHT_LEVEL,
Unit.INSTANCE
))
);
}
// collect futures and trigger relight once all chunks are loaded
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v ->
invokeRelight(
coords,
c -> {
}, // no callback for single chunks required
i -> {
if (i != coords.size()) {
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
}
// post process chunks on main thread
TaskManager.taskManager().task(() -> postProcessChunks(coords));
// call callback on our own threads
TaskManager.taskManager().async(andThen);
}
)
);
});
}
private void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
private void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(serverLevel, x, z, false);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
@Override
public void clear() {
}
@Override
public void removeLighting() {
this.delegate.removeLighting();
}
@Override
public void fixBlockLighting() {
fixLightingSafe(true);
}
@Override
public void fixSkyLighting() {
fixLightingSafe(true);
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public ReentrantLock getLock() {
return this.lock;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public void close() throws Exception {
fixLightingSafe(true);
}
}

Datei anzeigen

@ -1,594 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen;
import com.fastasyncworldedit.bukkit.adapter.Regenerator;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightGetBlocks;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
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.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;
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.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;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
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.Chunk;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field flatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
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<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.FULL
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
/*chunkStati.put(
ChunkStatus.LIQUID_CARVERS,
Concurrency.NONE
); // liquid carvers: radius 0, but RADIUS and FULL change results*/
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
// chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I"));
chunkSourceField.setAccessible(true);
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v"));
generatorStructureStateField.setAccessible(true);
ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(
Refraction.pickName("hasGeneratedPositions", "h")
);
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureTemplateManager structureTemplateManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
if (!(originalChunkProvider instanceof ServerChunkCache)) {
return false;
}
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
.getOrThrow(levelStemResourceKey),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalServerWorld.getRandomSequences(),
environment,
generator,
biomeProvider
) {
private final Holder<Biome> 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 Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
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());
}
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator();
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Holder<NoiseGeneratorSettings>) generatorSettingBaseSupplierField.get(
originalGenerator);
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(
DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
)
);
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(
biomeSource,
generatorSettingBaseSupplier
);
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.getDelegate();
} else {
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,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
freshWorld.spigotConfig.simulationDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap);
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> origPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(state);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(
origPositions);
ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap);
ringPositionsField.set(newState, copy);
hasGeneratedPositionsField.setBoolean(newState, true);
}
}
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureTemplateManager = server.getStructureManager();
threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider);
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld,
this.freshWorld.registryAccess().registryOrThrow(BIOME), null
);
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> {
final CraftWorld world = freshWorld.getWorld();
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
blockPopulator.populate(world, random, chunk);
});
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
public FastProtoChunk(
final ChunkPos pos,
final UpgradeData upgradeData,
final LevelHeightAccessor world,
final Registry<Biome> biomeRegistry,
@Nullable final BlendingData blendingData
) {
super(pos, upgradeData, world, biomeRegistry, blendingData);
}
// avoid warning on paper
// compatibility with spigot
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return chunkStatus.getRange();
}
@Override
public String name() {
return chunkStatus.toString();
}
@Override
public CompletableFuture<?> processChunk(Long xz, List<ChunkAccess> accessibleChunks) {
return chunkStatus.generate(
Runnable::run, // TODO revisit, we might profit from this somehow?
freshWorld,
chunkGenerator,
structureTemplateManager,
threadedLevelLightEngine,
c -> CompletableFuture.completedFuture(Either.left(c)),
accessibleChunks
);
}
}
/**
* A light engine that does nothing. As light is calculated after pasting anyway, we can avoid
* work this way.
*/
static class NoOpLightEngine extends ThreadedLevelLightEngine {
private static final ProcessorMailbox<Runnable> MAILBOX = ProcessorMailbox.create(task -> {
}, "fawe-no-op");
private static final ProcessorHandle<Message<Runnable>> HANDLE = ProcessorHandle.of("fawe-no-op", m -> {
});
public NoOpLightEngine(final ServerChunkCache chunkProvider) {
super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE);
}
@Override
public CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) {
return CompletableFuture.completedFuture(chunk);
}
}
}

Datei anzeigen

@ -11,7 +11,7 @@ repositories {
} }
dependencies { 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.20.2-R0.1-SNAPSHOT
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.18.2-R0.1-20220920.010157-167") the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.2-R0.1-20231203.034718-121")
compileOnly(libs.paperlib) compileOnly(libs.paperlib)
} }

Datei anzeigen

@ -17,17 +17,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTConstants;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItem;
@ -55,22 +55,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.DoubleBinaryTag;
import com.sk89q.worldedit.util.nbt.EndBinaryTag;
import com.sk89q.worldedit.util.nbt.FloatBinaryTag;
import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.IntBinaryTag;
import com.sk89q.worldedit.util.nbt.ListBinaryTag;
import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.LongBinaryTag;
import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -81,6 +68,9 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -92,6 +82,7 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable; import net.minecraft.world.Clearable;
@ -122,21 +113,39 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.enginehub.linbus.common.LinTagId;
import org.enginehub.linbus.tree.LinByteArrayTag;
import org.enginehub.linbus.tree.LinByteTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinEndTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinIntArrayTag;
import org.enginehub.linbus.tree.LinIntTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinLongArrayTag;
import org.enginehub.linbus.tree.LinLongTag;
import org.enginehub.linbus.tree.LinShortTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import org.enginehub.linbus.tree.LinTagType;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -144,6 +153,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -158,20 +168,21 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> { public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> {
private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
private final Field serverWorldsField; private final Field serverWorldsField;
private final Method getChunkFutureMethod; private final Method getChunkFutureMethod;
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -181,8 +192,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
CraftServer.class.cast(Bukkit.getServer()); CraftServer.class.cast(Bukkit.getServer());
int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion();
if (dataVersion != 3337) { if (dataVersion != 3578) {
throw new UnsupportedClassVersionError("Not 1.19.4!"); throw new UnsupportedClassVersionError("Not 1.20.2!");
} }
serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField = CraftServer.class.getDeclaredField("worlds");
@ -280,12 +291,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static Block getBlockFromType(BlockType blockType) { private static Block getBlockFromType(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id()));
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.getId()));
} }
private static Item getItemFromType(ItemType itemType) { private static Item getItemFromType(ItemType itemType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.getId())); return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id()));
} }
@Override @Override
@ -305,6 +315,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId);
} }
public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
int internalId = Block.getId(blockState);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
state = BukkitAdapter.adapt(CraftBlockData.createData(blockState));
}
return state;
}
public BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId);
}
@Override @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -318,14 +351,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData); return adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
} }
@Override @Override
@ -345,14 +371,48 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockEntity te = chunk.getBlockEntity(blockPos); BlockEntity te = chunk.getBlockEntity(blockPos);
if (te != null) { if (te != null) {
net.minecraft.nbt.CompoundTag tag = te.saveWithId(); net.minecraft.nbt.CompoundTag tag = te.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
return state.toBaseBlock(); return state.toBaseBlock();
} }
private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>();
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public BiomeType getBiome(Location location) {
checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString()));
}
@Override
public void setBiome(Location location, BiomeType biome) {
checkNotNull(location);
checkNotNull(biome);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id())))));
chunk.setUnsaved(true);
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new PaperweightWorldNativeAccess(this, return new PaperweightWorldNativeAccess(this,
new WeakReference<>(((CraftWorld) world).getHandle())); new WeakReference<>(((CraftWorld) world).getHandle()));
} }
@ -425,7 +485,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
readEntityIntoTag(mcEntity, tag); readEntityIntoTag(mcEntity, tag);
return new BaseEntity( return new BaseEntity(
com.sk89q.worldedit.world.entity.EntityTypes.get(id), com.sk89q.worldedit.world.entity.EntityTypes.get(id),
LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))
); );
} }
@ -438,12 +498,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
CraftWorld craftWorld = ((CraftWorld) location.getWorld()); CraftWorld craftWorld = ((CraftWorld) location.getWorld());
ServerLevel worldServer = craftWorld.getHandle(); ServerLevel worldServer = craftWorld.getHandle();
Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle());
if (createdEntity != null) { if (createdEntity != null) {
CompoundBinaryTag nativeTag = state.getNbt(); LinCompoundTag nativeTag = state.getNbt();
if (nativeTag != null) { if (nativeTag != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag);
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
@ -491,21 +551,39 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
.newBuilder()
.build(new CacheLoader<>() {
@Override @Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) { } else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(), return new DirectionalProperty(
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); state.getName(),
new ArrayList<>((List<Direction>) state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName()
.toUpperCase(Locale.ROOT)))
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(), return new EnumProperty(
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else { } else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
} }
} }
}); });
@ -525,13 +603,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) {
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
new StructureBlockEntity( new StructureBlockEntity(
new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), new BlockPos(pos.x(), pos.y(), pos.z()),
Blocks.STRUCTURE_BLOCK.defaultBlockState() Blocks.STRUCTURE_BLOCK.defaultBlockState()
), ),
__ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData)
)); ));
} }
@ -545,7 +623,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount() item.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
@ -556,7 +634,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag()));
return weStack; return weStack;
} }
@ -578,15 +656,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; return false;
} }
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), fakePlayer.absMoveTo(position.x(), position.y(), position.z(),
(float) face.toVector().toYaw(), (float) face.toVector().toPitch()); (float) face.toVector().toYaw(), (float) face.toVector().toPitch());
final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
final net.minecraft.core.Direction enumFacing = adapt(face); final net.minecraft.core.Direction enumFacing = adapt(face);
BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false);
UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace);
InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND); InteractionResult result = stack.useOn(context);
if (result != InteractionResult.SUCCESS) { if (result != InteractionResult.SUCCESS) {
if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) { if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) {
result = InteractionResult.SUCCESS; result = InteractionResult.SUCCESS;
@ -599,14 +677,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.getX(), position.getY(), position.getZ())); return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
} }
@Override @Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) {
try { try {
doRegen(bukkitWorld, region, extent, options); doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) { } catch (Exception e) {
@ -616,7 +694,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true; return true;
} }
private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
Environment env = bukkitWorld.getEnvironment(); Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator(); ChunkGenerator gen = bukkitWorld.getGenerator();
@ -644,6 +722,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
levelProperties.settings.getDataConfiguration() levelProperties.settings.getDataConfiguration()
); );
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty = PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld() levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT ? PrimaryLevelData.SpecialWorldProperty.FLAT
@ -667,6 +746,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
seed, seed,
ImmutableList.of(), ImmutableList.of(),
false, false,
originalWorld.getRandomSequences(),
env, env,
gen, gen,
bukkitWorld.getBiomeProvider() bukkitWorld.getBiomeProvider()
@ -679,7 +759,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer()); Map<String, World> map = (Map<String, World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -722,7 +802,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
for (BlockVector3 vec : region) { for (BlockVector3 vec : region) {
BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z());
ChunkAccess chunk = chunks.get(new ChunkPos(pos)); ChunkAccess chunk = chunks.get(new ChunkPos(pos));
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos);
int internalId = Block.getId(blockData); int internalId = Block.getId(blockData);
@ -731,11 +811,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockEntity blockEntity = chunk.getBlockEntity(pos); BlockEntity blockEntity = chunk.getBlockEntity(pos);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
extent.setBlock(vec, state.toBaseBlock()); extent.setBlock(vec, state.toBaseBlock());
if (options.shouldRegenBiomes()) { if (options.shouldRegenBiomes()) {
Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value();
BiomeType adaptedBiome = adapt(serverWorld, origBiome); BiomeType adaptedBiome = adapt(serverWorld, origBiome);
if (adaptedBiome != null) { if (adaptedBiome != null) {
extent.setBiome(vec, adaptedBiome); extent.setBiome(vec, adaptedBiome);
@ -754,7 +834,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
//noinspection unchecked //noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>) ((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null)) .thenApply(either -> either.left().orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
@ -791,10 +871,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
if (entity instanceof Clearable) { if (entity instanceof Clearable) {
((Clearable) entity).clearContent(); ((Clearable) entity).clearContent();
return true; return true;
@ -802,6 +882,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; return false;
} }
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
@Override
public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
List<ChunkAccess> nativeChunks = chunks instanceof Collection<BlockVector2> chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList();
for (BlockVector2 chunk : chunks) {
nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false));
}
originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that is less likely to break // Code that is less likely to break
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -814,51 +933,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @return native WorldEdit NBT structure * @return native WorldEdit NBT structure
*/ */
@Override @Override
public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { public LinTag<?> toNativeLin(net.minecraft.nbt.Tag foreign) {
if (foreign == null) { if (foreign == null) {
return null; return null;
} }
if (foreign instanceof net.minecraft.nbt.CompoundTag) { if (foreign instanceof net.minecraft.nbt.CompoundTag) {
Map<String, BinaryTag> values = new HashMap<>(); Map<String, LinTag<?>> values = new HashMap<>();
Set<String> foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); Set<String> foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys();
for (String str : foreignKeys) { for (String str : foreignKeys) {
net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str);
values.put(str, toNativeBinary(base)); values.put(str, toNativeLin(base));
} }
return CompoundBinaryTag.from(values); return LinCompoundTag.of(values);
} else if (foreign instanceof net.minecraft.nbt.ByteTag) { } else if (foreign instanceof net.minecraft.nbt.ByteTag) {
return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte());
} else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) {
return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray());
} else if (foreign instanceof net.minecraft.nbt.DoubleTag) { } else if (foreign instanceof net.minecraft.nbt.DoubleTag) {
return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble());
} else if (foreign instanceof net.minecraft.nbt.FloatTag) { } else if (foreign instanceof net.minecraft.nbt.FloatTag) {
return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat());
} else if (foreign instanceof net.minecraft.nbt.IntTag) { } else if (foreign instanceof net.minecraft.nbt.IntTag) {
return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt());
} else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) {
return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray());
} else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) {
return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray());
} else if (foreign instanceof net.minecraft.nbt.ListTag) { } else if (foreign instanceof net.minecraft.nbt.ListTag) {
try { try {
return toNativeList((net.minecraft.nbt.ListTag) foreign); return toNativeLinList((net.minecraft.nbt.ListTag) foreign);
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
return ListBinaryTag.empty();
} }
} else if (foreign instanceof net.minecraft.nbt.LongTag) { } else if (foreign instanceof net.minecraft.nbt.LongTag) {
return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong());
} else if (foreign instanceof net.minecraft.nbt.ShortTag) { } else if (foreign instanceof net.minecraft.nbt.ShortTag) {
return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort());
} else if (foreign instanceof net.minecraft.nbt.StringTag) { } else if (foreign instanceof net.minecraft.nbt.StringTag) {
return StringBinaryTag.of(foreign.getAsString()); return LinStringTag.of(foreign.getAsString());
} else if (foreign instanceof net.minecraft.nbt.EndTag) { } else if (foreign instanceof net.minecraft.nbt.EndTag) {
return EndBinaryTag.get(); return LinEndTag.instance();
} else {
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
} }
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
} }
/** /**
@ -869,14 +986,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @throws SecurityException on error * @throws SecurityException on error
* @throws IllegalArgumentException on error * @throws IllegalArgumentException on error
*/ */
private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { private LinListTag<?> toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException {
ListBinaryTag.Builder values = ListBinaryTag.builder(); LinListTag.Builder<LinTag<?>> builder = LinListTag.builder(
LinTagType.fromId(LinTagId.fromId(foreign.getElementType()))
);
for (net.minecraft.nbt.Tag tag : foreign) { for (net.minecraft.nbt.Tag tag : foreign) {
values.add(toNativeBinary(tag)); builder.add(toNativeLin(tag));
} }
return values.build(); return builder.build();
} }
/** /**
@ -886,44 +1005,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @return non-native structure * @return non-native structure
*/ */
@Override @Override
public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { public net.minecraft.nbt.Tag fromNativeLin(LinTag<?> foreign) {
if (foreign == null) { if (foreign == null) {
return null; return null;
} }
if (foreign instanceof CompoundBinaryTag) { if (foreign instanceof LinCompoundTag compoundTag) {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
for (String key : ((CompoundBinaryTag) foreign).keySet()) { for (var entry : compoundTag.value().entrySet()) {
tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); tag.put(entry.getKey(), fromNativeLin(entry.getValue()));
} }
return tag; return tag;
} else if (foreign instanceof ByteBinaryTag) { } else if (foreign instanceof LinByteTag byteTag) {
return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte());
} else if (foreign instanceof ByteArrayBinaryTag) { } else if (foreign instanceof LinByteArrayTag byteArrayTag) {
return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value());
} else if (foreign instanceof DoubleBinaryTag) { } else if (foreign instanceof LinDoubleTag doubleTag) {
return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble());
} else if (foreign instanceof FloatBinaryTag) { } else if (foreign instanceof LinFloatTag floatTag) {
return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat());
} else if (foreign instanceof IntBinaryTag) { } else if (foreign instanceof LinIntTag intTag) {
return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt());
} else if (foreign instanceof IntArrayBinaryTag) { } else if (foreign instanceof LinIntArrayTag intArrayTag) {
return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.IntArrayTag(intArrayTag.value());
} else if (foreign instanceof LongArrayBinaryTag) { } else if (foreign instanceof LinLongArrayTag longArrayTag) {
return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.LongArrayTag(longArrayTag.value());
} else if (foreign instanceof ListBinaryTag) { } else if (foreign instanceof LinListTag<?> listTag) {
net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag();
ListBinaryTag foreignList = (ListBinaryTag) foreign; for (var t : listTag.value()) {
for (BinaryTag t : foreignList) { tag.add(fromNativeLin(t));
tag.add(fromNativeBinary(t));
} }
return tag; return tag;
} else if (foreign instanceof LongBinaryTag) { } else if (foreign instanceof LinLongTag longTag) {
return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong());
} else if (foreign instanceof ShortBinaryTag) { } else if (foreign instanceof LinShortTag shortTag) {
return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort());
} else if (foreign instanceof StringBinaryTag) { } else if (foreign instanceof LinStringTag stringTag) {
return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); return net.minecraft.nbt.StringTag.valueOf(stringTag.value());
} else if (foreign instanceof EndBinaryTag) { } else if (foreign instanceof LinEndTag) {
return net.minecraft.nbt.EndTag.INSTANCE; return net.minecraft.nbt.EndTag.INSTANCE;
} else { } else {
throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName());
@ -962,7 +1080,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
WatchdogThread.tick(); WatchdogThread.tick();
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); logger.log(Level.WARNING, "Failed to tick watchdog", e);
} }
} }
} }
@ -974,7 +1092,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server; this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField( Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah") Refraction.pickName("nextTickTime", "ag")
); );
if (tickField.getType() != long.class) { if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -35,7 +35,6 @@ import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic; import com.mojang.serialization.Dynamic;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@ -48,7 +47,9 @@ import net.minecraft.util.datafix.fixes.References;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
@ -62,7 +63,6 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.stream.Collectors; 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) * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2)
@ -76,18 +76,17 @@ import javax.annotation.Nullable;
* receive the source version in the compound * receive the source version in the compound
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer {
//FAWE start - BinaryTag
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T fixUp(FixType<T> type, T original, int srcVer) { public <T> T fixUp(FixType<T> type, T original, int srcVer) {
if (type == FixTypes.CHUNK) { if (type == FixTypes.CHUNK) {
return (T) fixChunk((CompoundBinaryTag) original, srcVer); return (T) fixChunk((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_ENTITY) { } else if (type == FixTypes.BLOCK_ENTITY) {
return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); return (T) fixBlockEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.ENTITY) { } else if (type == FixTypes.ENTITY) {
return (T) fixEntity((CompoundBinaryTag) original, srcVer); return (T) fixEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_STATE) { } else if (type == FixTypes.BLOCK_STATE) {
return (T) fixBlockState((String) original, srcVer); return (T) fixBlockState((String) original, srcVer);
} else if (type == FixTypes.ITEM_TYPE) { } else if (type == FixTypes.ITEM_TYPE) {
@ -98,24 +97,23 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return original; return original;
} }
private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
//FAWE end
private String fixBlockState(String blockState, int srcVer) { private String fixBlockState(String blockState, int srcVer) {
net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState);
@ -173,7 +171,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private static final NbtOps OPS_NBT = NbtOps.INSTANCE; private static final NbtOps OPS_NBT = NbtOps.INSTANCE;
private static final int LEGACY_VERSION = 1343; private static final int LEGACY_VERSION = 1343;
private static int DATA_VERSION; private static int DATA_VERSION;
static PaperweightDataConverters INSTANCE; public static PaperweightDataConverters INSTANCE;
private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class);
private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class);
@ -204,7 +202,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
} }
} }
PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) {
super(dataVersion); super(dataVersion);
DATA_VERSION = dataVersion; DATA_VERSION = dataVersion;
INSTANCE = this; INSTANCE = this;

Datei anzeigen

@ -17,17 +17,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component; 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.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat; import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity; 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.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
@ -38,9 +40,12 @@ import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer { 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 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) { PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO);
} }
@Override @Override
@ -67,7 +72,7 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void updateOptions(ServerboundClientInformationPacket packet) { public void updateOptions(ClientInformation clientOptions) {
} }
@Override @Override

Datei anzeigen

@ -17,9 +17,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
@ -27,17 +26,20 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -101,9 +103,16 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
@Override @Override
public boolean updateTileEntity(BlockPos position, CompoundBinaryTag tag) { public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false; return false;
} }
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override @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) {
@ -144,6 +153,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -153,8 +168,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @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(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();

Datei anzeigen

@ -1,10 +1,8 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.util.ReflectionUtil; import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
@ -15,7 +13,9 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import javax.annotation.Nullable;
public class PaperweightBlockMaterial implements BlockMaterial { public class PaperweightBlockMaterial implements BlockMaterial {
@ -25,7 +25,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
private final int opacity; private final int opacity;
private final CompoundTag tile; private final FaweCompoundTag tile;
public PaperweightBlockMaterial(Block block) { public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState()); this(block, block.defaultBlockState());
@ -48,7 +48,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
); );
tile = tileEntity == null tile = tileEntity == null
? null ? null
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
} }
public Block getBlock() { public Block getBlock() {
@ -135,9 +135,10 @@ public class PaperweightBlockMaterial implements BlockMaterial {
return block.isRandomlyTicking(blockState); return block.isRandomlyTicking(blockState);
} }
@SuppressWarnings("deprecation")
@Override @Override
public boolean isMovementBlocker() { public boolean isMovementBlocker() {
return craftMaterial.isSolid(); return blockState.blocksMotion();
} }
@Override @Override
@ -172,7 +173,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
} }
@Override @Override
public CompoundTag getDefaultTile() { public @Nullable FaweCompoundTag defaultTile() {
return tile; return tile;
} }

Datei anzeigen

@ -1,28 +1,24 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitAdapter; 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.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.regen.PaperweightRegen;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -38,11 +34,7 @@ import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; 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.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -77,19 +69,20 @@ import net.minecraft.world.level.chunk.LevelChunk;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -105,14 +98,14 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static net.minecraft.core.registries.Registries.BIOME; import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.Tag, ServerLevel> {
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
@ -124,18 +117,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
} }
private final PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new PaperweightAdapter(); super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter());
}
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
return blockEntity -> FaweCompoundTag.of(
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId())
);
} }
@Nullable @Nullable
@ -248,11 +239,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -268,12 +258,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseBlock getFullBlock(final Location location) { public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -288,7 +277,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
} }
@ -302,10 +291,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess( return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world)));
this,
new WeakReference<>(((CraftWorld) world).getHandle())
);
} }
@Override @Override
@ -319,14 +305,14 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { Supplier<LinCompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, LinTag<?>> tags = NbtUtils.getLinCompoundTagValues(tag);
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", LinStringTag.of(id));
return CompoundBinaryTag.from(tags); return LinCompoundTag.of(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -450,7 +436,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { 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()); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && wasAccessibleSinceLastSave(map)) { if (map != null && wasAccessibleSinceLastSave(map)) {
boolean flag = false; boolean flag = false;
@ -488,8 +474,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess( return blockState1.hasPostProcess(
((CraftWorld) world).getHandle(), getServerLevel(world),
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z())
); );
} }
@ -497,7 +483,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM)
.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), .get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount() baseItemStack.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
@ -505,54 +491,33 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
@Override @Override
public boolean generateTree( protected void preCaptureStates(final ServerLevel serverLevel) {
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<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
} }
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally { @Override
protected List<org.bukkit.block.BlockState> getCapturedBlockStatesCopy(final ServerLevel serverLevel) {
return new ArrayList<>(serverLevel.capturedBlockStates.values());
}
@Override
protected void postCaptureBlockStates(final ServerLevel serverLevel) {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
} }
});
if (placed == null || placed.isEmpty()) { @Override
return false; protected ServerLevel getServerLevel(final World world) {
} return ((CraftWorld) world).getHandle();
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;
} }
@Override @Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag())));
return weStack; return weStack;
} }
@ -585,7 +550,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
.getServer() .getServer()
.registryAccess() .registryAccess()
.registryOrThrow(BIOME); .registryOrThrow(BIOME);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id());
Biome biome = registry.get(resourceLocation); Biome biome = registry.get(resourceLocation);
return registry.getId(biome); return registry.getId(biome);
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.math.IntPair;
@ -9,22 +9,21 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; 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.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -133,14 +132,14 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
@Override @Override
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) {
// We will assume that the tile entity was created for us, // We will assume that the tile entity was created for us,
// though we do not do this on the other versions // though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) { if (blockEntity == null) {
return false; return false;
} }
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag);
blockEntity.load((CompoundTag) nativeTag); blockEntity.load((CompoundTag) nativeTag);
return true; return true;
} }
@ -218,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,
@ -247,7 +252,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };
@ -263,7 +268,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -7,21 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -35,6 +31,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
@ -54,16 +51,24 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette; import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTagType;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.AbstractSet; import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -76,42 +81,49 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport; import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
private static final Function<BlockEntity, CompoundTag> nmsTile2We = public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); .getInstance()
.getBukkitImplAdapter()).blockEntityToCompoundTag();
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
.getInstance() .getInstance()
.getBukkitImplAdapter()); .getBukkitImplAdapter());
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
private final ReentrantLock callLock = new ReentrantLock();
private final ServerLevel serverLevel; private final ServerLevel serverLevel;
private final int chunkX; private final int chunkX;
private final int chunkZ; private final int chunkZ;
private final IntPair chunkPos;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
private final int minSectionPosition; private final int minSectionPosition;
private final int maxSectionPosition; private final int maxSectionPosition;
private final Registry<Biome> biomeRegistry; private final Registry<Biome> biomeRegistry;
private final IdMap<Holder<Biome>> biomeHolderIdMap; private final IdMap<Holder<Biome>> biomeHolderIdMap;
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
private final Object sendLock = new Object();
private LevelChunkSection[] sections; private LevelChunkSection[] sections;
private LevelChunk levelChunk; private LevelChunk levelChunk;
private DataLayer[] blockLight; private DataLayer[] blockLight;
private DataLayer[] skyLight; private DataLayer[] skyLight;
private boolean createCopy = false; private boolean createCopy = false;
private PaperweightGetBlocks_Copy copy = null;
private boolean forceLoadSections = true; private boolean forceLoadSections = true;
private boolean lightUpdate = false; private boolean lightUpdate = false;
private int copyKey = 0;
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ); this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -128,8 +140,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.maxSectionPosition = maxHeight >> 4; this.maxSectionPosition = maxHeight >> 4;
this.skyLight = new DataLayer[getSectionCount()]; this.skyLight = new DataLayer[getSectionCount()];
this.blockLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()];
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
this.chunkPos = new IntPair(chunkX, chunkZ);
} }
public int getChunkX() { public int getChunkX() {
@ -146,13 +159,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
}
this.createCopy = createCopy; this.createCopy = createCopy;
// Increment regardless of whether copy will be created or not to return null from getCopy()
return ++this.copyKey;
} }
@Override @Override
public IChunkGet getCopy() { public IChunkGet getCopy(final int key) {
return copy; return copies.remove(key);
}
@Override
public void lockCall() {
this.callLock.lock();
}
@Override
public void unlockCall() {
this.callLock.unlock();
} }
@Override @Override
@ -236,23 +264,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getTile(int x, int y, int z) { public FaweCompoundTag tile(final int x, final int y, final int z) {
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
chunkX << 4), y, (z & 15) + ( chunkX << 4), y, (z & 15) + (
chunkZ << 4))); chunkZ << 4)));
if (blockEntity == null) { if (blockEntity == null) {
return null; return null;
} }
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); return NMS_TO_TILE.apply(blockEntity);
} }
@Override @Override
public Map<BlockVector3, CompoundTag> getTiles() { public Map<BlockVector3, FaweCompoundTag> tiles() {
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities(); Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
if (nmsTiles.isEmpty()) { if (nmsTiles.isEmpty()) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
} }
@Override @Override
@ -272,8 +301,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
LightLayer.BLOCK, LightLayer.BLOCK,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
skyLight[alayer] = dataLayer; skyLight[alayer] = dataLayer;
@ -300,7 +328,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
Arrays.fill(LAYER_COUNT, (byte) 15); Arrays.fill(LAYER_COUNT, (byte) 15);
dataLayer = new DataLayer(LAYER_COUNT); dataLayer = new DataLayer(LAYER_COUNT);
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos,
dataLayer, true dataLayer
); );
} }
blockLight[alayer] = dataLayer; blockLight[alayer] = dataLayer;
@ -316,14 +344,22 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
Entity entity = serverLevel.getEntity(uuid); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
Entity entity = null;
for (Entity e : entities) {
if (e.getUUID().equals(uuid)) {
entity = e;
break;
}
}
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
} }
for (CompoundTag tag : getEntities()) { for (FaweCompoundTag tag : entities()) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -331,13 +367,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
if (entities.isEmpty()) { if (entities.isEmpty()) {
return Collections.emptySet(); return Collections.emptyList();
} }
int size = entities.size(); int size = entities.size();
return new AbstractSet<>() { return new AbstractCollection<>() {
@Override @Override
public int size() { public int size() {
return size; return size;
@ -350,10 +387,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public boolean contains(Object get) { public boolean contains(Object get) {
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof FaweCompoundTag getTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); UUID getUUID = NbtUtils.uuid(getTag);
for (Entity entity : entities) { for (Entity entity : entities) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
@ -365,12 +402,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Nonnull @Nonnull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<FaweCompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); CompoundTag tag = new CompoundTag();
input.save(tag); input.save(tag);
return (CompoundTag) adapter.toNative(tag); return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
}).collect(Collectors.toList()); })::iterator;
return result.iterator(); return result.iterator();
} }
}; };
@ -387,12 +424,19 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
}
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
if (createCopy) {
if (copies.containsKey(copyKey)) {
throw new IllegalStateException("Copy key already used.");
}
copies.put(copyKey, copy);
}
try { try {
ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
// Remove existing tiles. Create a copy so that we can remove blocks // Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
List<BlockEntity> beacons = null; List<BlockEntity> beacons = null;
@ -448,7 +492,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
synchronized (super.sectionLocks[getSectionIndex]) { synchronized (super.sectionLocks[getSectionIndex]) {
LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
if (createCopy && existingSection != null) { if (createCopy && existingSection != null) {
copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
} }
if (existingSection == null) { if (existingSection == null) {
@ -464,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -481,8 +527,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
PalettedContainer<Holder<Biome>> biomeData = existingSection.getBiomes(); PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (paletteBiomes != null) {
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
}
} }
} }
} }
@ -517,20 +569,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
copy.storeSection(getSectionIndex, copyArr); copy.storeSection(getSectionIndex, copyArr);
if (biomes != null && existingSection != null) { if (biomes != null && existingSection != null) {
copy.storeBiomes(getSectionIndex, existingSection.getBiomes().copy()); copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
} }
} }
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance() PalettedContainer.Strategy.SECTION_BIOMES
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
@ -540,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -590,22 +639,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
sectionLock.writeLock().unlock(); sectionLock.writeLock().unlock();
} }
PalettedContainer<Holder<Biome>> biomeData = existingSection.getBiomes(); PalettedContainer<Holder<Biome>> biomeData = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (biomes != null && biomes[setSectionIndex] != null) { newSection = PaperweightPlatformAdapter.newChunkSection(
setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData);
}
newSection =
PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
this::loadPrivately, this::loadPrivately,
setArr, setArr,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
); );
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
existingSection, existingSection,
newSection, newSection,
@ -679,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) { for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); Entity entity = serverLevel.getEntities().get(uuid);
if (entity != null) { if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
@ -691,48 +741,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
}; };
} }
Set<CompoundTag> entities = set.getEntities(); Collection<FaweCompoundTag> entities = set.entities();
if (entities != null && !entities.isEmpty()) { if (entities != null && !entities.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[2]; syncTasks = new Runnable[2];
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); Iterator<FaweCompoundTag> iterator = entities.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final CompoundTag nativeTag = iterator.next(); final FaweCompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final LinCompoundTag linTag = nativeTag.linTag();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
if (idTag == null || posTag == null || rotTag == null) { if (idTag == null || posTag == null || rotTag == null) {
LOGGER.error("Unknown entity tag: {}", nativeTag); LOGGER.error("Unknown entity tag: {}", nativeTag);
continue; continue;
} }
final double x = posTag.getDouble(0); final double x = posTag.get(0).valueAsDouble();
final double y = posTag.getDouble(1); final double y = posTag.get(1).valueAsDouble();
final double z = posTag.getDouble(2); final double z = posTag.get(2).valueAsDouble();
final float yaw = rotTag.getFloat(0); final float yaw = rotTag.get(0).valueAsFloat();
final float pitch = rotTag.getFloat(1); final float pitch = rotTag.get(1).valueAsFloat();
final String id = idTag.getValue(); final String id = idTag.value();
EntityType<?> type = EntityType.byString(id).orElse(null); EntityType<?> type = EntityType.byString(id).orElse(null);
if (type != null) { if (type != null) {
Entity entity = type.create(nmsWorld); Entity entity = type.create(serverLevel);
if (entity != null) { if (entity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); entity.setUUID(NbtUtils.uuid(nativeTag));
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn( LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`", "Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id, id,
nmsWorld.getWorld().getName(), serverLevel.getWorld().getName(),
x, x,
y, y,
z z
@ -747,30 +796,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
// set tiles // set tiles
Map<BlockVector3, CompoundTag> tiles = set.getTiles(); Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
if (tiles != null && !tiles.isEmpty()) { if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[1]; syncTasks = new Runnable[1];
} }
syncTasks[0] = () -> { syncTasks[0] = () -> {
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) { for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue(); final FaweCompoundTag nativeTag = entry.getValue();
final BlockVector3 blockHash = entry.getKey(); final BlockVector3 blockHash = entry.getKey();
final int x = blockHash.getX() + bx; final int x = blockHash.x() + bx;
final int y = blockHash.getY(); final int y = blockHash.y();
final int z = blockHash.getZ() + bz; final int z = blockHash.z() + bz;
final BlockPos pos = new BlockPos(x, y, z); final BlockPos pos = new BlockPos(x, y, z);
synchronized (nmsWorld) { synchronized (serverLevel) {
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
if (tileEntity == null || tileEntity.isRemoved()) { if (tileEntity == null || tileEntity.isRemoved()) {
nmsWorld.removeBlockEntity(pos); serverLevel.removeBlockEntity(pos);
tileEntity = nmsWorld.getBlockEntity(pos); tileEntity = serverLevel.getBlockEntity(pos);
} }
if (tileEntity != null) { if (tileEntity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
nativeTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
@ -786,15 +834,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
callback = null; callback = null;
} else { } else {
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
boolean finalLightUpdate = lightUpdate;
callback = () -> { callback = () -> {
// Set Modified // Set Modified
nmsChunk.setLightCorrect(true); // Set Modified nmsChunk.setLightCorrect(true); // Set Modified
nmsChunk.mustNotSave = false; nmsChunk.mustNotSave = false;
nmsChunk.setUnsaved(true); nmsChunk.setUnsaved(true);
// send to player // send to player
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
this.send(finalMask, finalLightUpdate); this.send();
} }
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); finalizer.run();
@ -816,7 +863,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -882,9 +929,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (super.sections[layer] != null) { if (super.sections[layer] != null) {
synchronized (super.sectionLocks[layer]) { synchronized (super.sectionLocks[layer]) {
if (super.sections[layer].isFull() && super.blocks[layer] != null) { if (super.sections[layer].isFull() && super.blocks[layer] != null) {
char[] blocks = new char[4096]; return super.blocks[layer];
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
return blocks;
} }
} }
} }
@ -892,8 +937,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send() {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
}
} }
/** /**
@ -1004,9 +1051,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
public LevelChunkSection[] getSections(boolean force) { public LevelChunkSection[] getSections(boolean force) {
force &= forceLoadSections; force &= forceLoadSections;
sectionLock.readLock().lock();
LevelChunkSection[] tmp = sections; LevelChunkSection[] tmp = sections;
sectionLock.readLock().unlock();
if (tmp == null || force) { if (tmp == null || force) {
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
@ -1052,8 +1097,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
lightLayer, lightLayer,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
synchronized (dataLayer) { synchronized (dataLayer) {
@ -1071,34 +1115,35 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
private void setBiomesToPalettedContainer( private PalettedContainer<Holder<Biome>> setBiomesToPalettedContainer(
final BiomeType[] biomes, final BiomeType[][] biomes,
PalettedContainer<Holder<Biome>> data final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data
) { ) {
int index = 0; BiomeType[] sectionBiomes;
if (biomes == null) { if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return; return null;
} }
for (int y = 0; y < 4; y++) { PalettedContainer<Holder<Biome>> biomeData = data.recreate();
for (int y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = biomes[index]; BiomeType biomeType = sectionBiomes[index];
if (biomeType == null) { if (biomeType == null) {
continue; biomeData.set(x, y, z, data.get(x, y, z));
} } else {
data.set( biomeData.set(
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }
} }
} }
return biomeData;
}
@Override @Override
public boolean hasSection(int layer) { public boolean hasSection(int layer) {

Datei anzeigen

@ -1,21 +1,22 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.util.NbtUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
@ -24,8 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -37,14 +41,14 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>(); private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>(); private final Set<FaweCompoundTag> entities = new HashSet<>();
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; final ServerLevel serverLevel;
final LevelChunk levelChunk; final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null; private Holder<Biome>[][] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk; this.levelChunk = levelChunk;
@ -55,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
protected void storeTile(BlockEntity blockEntity) { protected void storeTile(BlockEntity blockEntity) {
@SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
tiles.put( tiles.put(
BlockVector3.at( BlockVector3.at(
blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ() blockEntity.getBlockPos().getZ()
), ),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId()))
); );
} }
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); @SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag)); entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
return this.entities; return this.entities;
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
for (CompoundTag tag : entities) { for (FaweCompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -105,7 +100,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -142,7 +138,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
return PaperweightPlatformAdapter.adapt(biome, serverLevel); return PaperweightPlatformAdapter.adapt(biome, serverLevel);
} }
@ -171,10 +167,25 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) { protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) { if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()]; biomes = new Holder[getSectionCount()][];
}
if (biomes[layer] == null) {
biomes[layer] = new Holder[64];
} }
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomes[layer] = palettedContainer.copy(); if (PaperLib.isPaper()) {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
}
} else {
try {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} else { } else {
LOGGER.error( LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}", "Cannot correctly save biomes to history. Expected class type {} but got {}",
@ -187,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)]; BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z); return state.toBaseBlock((IBlocks) this, x, y, z);
} }
@Override @Override
@ -199,6 +210,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public char[] load(int layer) { public char[] load(int layer) {
layer -= getMinSectionPosition(); layer -= getMinSectionPosition();
if (blocks[layer] == null) {
blocks[layer] = new char[4096];
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
}
return blocks[layer]; return blocks[layer];
} }
@ -213,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return BlockTypesCache.states[get(x, y, z)]; return BlockTypesCache.states[get(x, y, z)];
} }
@Override
public Map<BlockVector3, FaweCompoundTag> tiles() {
return tiles;
}
@Override
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@Override @Override
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
return 0; return 0;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.destroystokyo.paper.util.maplist.EntityList; import com.destroystokyo.paper.util.maplist.EntityList;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
@ -26,6 +26,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -57,8 +58,7 @@ import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -98,21 +98,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector; private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock; private static final Field fieldLock;
private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity; private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldBiomes;
/* /*
* 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 * 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
@ -129,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static Field LEVEL_CHUNK_ENTITIES; private static Field LEVEL_CHUNK_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER; private static Field SERVER_LEVEL_ENTITY_MANAGER;
static final MethodHandle PALETTED_CONTAINER_GET;
static { static {
final MethodHandles.Lookup lookup = MethodHandles.lookup(); final MethodHandles.Lookup lookup = MethodHandles.lookup();
try { try {
@ -148,8 +144,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); Field tmpFieldBiomes;
fieldNonEmptyBlockCount.setAccessible(true); try {
// It seems to actually be biomes, but is apparently obfuscated to "i"
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
} catch (NoSuchFieldException ignored) {
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i");
}
fieldBiomes = tmpFieldBiomes;
fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -158,20 +161,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
getVisibleChunkIfPresent.setAccessible(true); getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) { if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetector.setAccessible(true);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); fieldLock.setAccessible(true);
} else { } else {
// in paper, the used methods are synchronized properly // in paper, the used methods are synchronized properly
fieldThreadingDetector = null; fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null; fieldLock = null;
fieldLockOffset = -1;
} }
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
@ -194,12 +192,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q"));
fieldRemove.setAccessible(true); fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
boolean chunkRewrite; boolean chunkRewrite;
try { try {
ServerLevel.class.getDeclaredMethod("getEntityLookup"); ServerLevel.class.getDeclaredMethod("getEntityLookup");
@ -222,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} catch (NoSuchFieldException ignored) { } catch (NoSuchFieldException ignored) {
} }
POST_CHUNK_REWRITE = chunkRewrite; POST_CHUNK_REWRITE = chunkRewrite;
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
Refraction.pickName("get", "a"),
int.class
);
palettedContaienrGet.setAccessible(true);
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
} catch (RuntimeException | Error e) { } catch (RuntimeException | Error e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -244,16 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
static boolean setSectionAtomic( static boolean setSectionAtomic(
String worldName,
IntPair pair,
LevelChunkSection[] sections, LevelChunkSection[] sections,
LevelChunkSection expected, LevelChunkSection expected,
LevelChunkSection value, LevelChunkSection value,
int layer int layer
) { ) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
} }
// There is no point in having a functional semaphore for paper servers. // There is no point in having a functional semaphore for paper servers.
@ -266,19 +263,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks);
blocks,
fieldThreadingDetectorOffset
);
synchronized (currentThreadingDetector) { synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) { if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore; return delegateSemaphore;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); fieldLock.set(currentThreadingDetector, newLock);
return newLock; return newLock;
} }
} }
@ -355,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) { if (chunkHolder == null) {
return; return;
@ -376,15 +369,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
if (levelChunk == null) { if (levelChunk == null) {
return; return;
} }
TaskManager.taskManager().task(() -> { StampLockHolder lockHolder = new StampLockHolder();
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
if (lockHolder.chunkLock == null) {
return;
}
MinecraftServer.getServer().execute(() -> {
try {
ClientboundLevelChunkWithLightPacket packet; ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket( packet = new ClientboundLevelChunkWithLightPacket(
levelChunk, levelChunk,
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
null, null,
null null,
// last false is to not bother with x-ray false // last false is to not bother with x-ray
); );
} else { } else {
// deprecated on paper - deprecation suppressed // deprecated on paper - deprecation suppressed
@ -396,6 +395,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
); );
} }
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
} finally {
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
}
}); });
} }
@ -425,7 +427,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -515,7 +517,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
@ -530,6 +531,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;

Datei anzeigen

@ -0,0 +1,77 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
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.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLevel, ChunkPos> {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT);
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<?> queue) {
super(serverLevel, queue);
}
@Override
protected ChunkPos createChunkPos(final long chunkKey) {
return new ChunkPos(chunkKey);
}
@Override
protected long asLong(final int chunkX, final int chunkZ) {
return ChunkPos.asLong(chunkX, chunkZ);
}
@Override
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
chunkPos,
LIGHT_LEVEL,
Unit.INSTANCE
));
}
protected void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
protected void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
}

Datei anzeigen

@ -1,23 +1,20 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class PaperweightStarlightRelighterFactory implements RelighterFactory { public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override @Override
public @Nonnull public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<?> queue) {
@SuppressWarnings("rawtypes")
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName()); org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) { if (w == null) {
return NullRelighter.INSTANCE; return NullRelighter.INSTANCE;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag; import com.sk89q.jnbt.LazyCompoundTag;
@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.NumericTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, Tag> getValue() { public Map<String, Tag<?, ?>> getValue() {
if (compoundTag == null) { if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
} }
@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@Override @Override
public CompoundBinaryTag asBinaryTag() { public LinCompoundTag toLinTag() {
getValue(); getValue();
return compoundTag.asBinaryTag(); return compoundTag.toLinTag();
} }
public boolean containsKey(String key) { public boolean containsKey(String key) {
@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<Tag> getList(String key) { public List<? extends Tag<?, ?>> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) { if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag> list = new ArrayList<>(); ArrayList<Tag<?, ?>> list = new ArrayList<>();
for (net.minecraft.nbt.Tag elem : nbtList) { for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag)); list.add(new PaperweightLazyCompoundTag(compoundTag));
@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) { public <T extends Tag<?, ?>> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key); ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) { if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue(); return (List<T>) listTag.getValue();

Datei anzeigen

@ -0,0 +1,303 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.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.queue.implementation.chunk.ChunkCache;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.ProgressListener;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.generator.BiomeProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Map;
import java.util.OptionalLong;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator {
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field generatorSettingBaseSupplierField;
static {
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
}
paperConfigField = tmpPaperConfigField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerLevel freshWorld;
private LevelStorageSource.LevelStorageAccess session;
private Path tempDir;
public PaperweightRegen(
World originalBukkitWorld,
Region region,
Extent target,
RegenOptions options
) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
while (shouldKeepTicking.getAsBoolean()) {
if (!this.freshWorld.getChunkSource().pollTask()) {
return;
}
}
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
seed = options.getSeed().orElse(originalServerWorld.getSeed());
return true;
}
@Override
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
new LevelStem(
originalServerWorld.dimensionTypeRegistration(),
originalServerWorld.getChunkSource().getGenerator()
),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalServerWorld.getRandomSequences(),
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
}
@Override
public void save(
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled
) {
// noop, spigot
}
@Override
public void save(
@Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled,
final boolean close
) {
// noop, paper
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
}
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshWorld.getChunkSource().getDataStorage().cache.clear();
freshWorld.getChunkSource().close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
}
@Override
public void onStatusChange(
final @NotNull ChunkPos pos,
@org.jetbrains.annotations.Nullable final ChunkStatus status
) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
}

Datei anzeigen

@ -11,6 +11,7 @@ repositories {
} }
dependencies { dependencies {
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.19.4-R0.1-20230608.201059-104") // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.4-R0.1-20241030.192207-176")
compileOnly(libs.paperlib) compileOnly(libs.paperlib)
} }

Datei anzeigen

@ -17,17 +17,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTConstants;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItem;
@ -55,22 +55,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.DoubleBinaryTag;
import com.sk89q.worldedit.util.nbt.EndBinaryTag;
import com.sk89q.worldedit.util.nbt.FloatBinaryTag;
import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.IntBinaryTag;
import com.sk89q.worldedit.util.nbt.ListBinaryTag;
import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag;
import com.sk89q.worldedit.util.nbt.LongBinaryTag;
import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -82,6 +69,8 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -93,6 +82,7 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable; import net.minecraft.world.Clearable;
@ -123,21 +113,39 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.enginehub.linbus.common.LinTagId;
import org.enginehub.linbus.tree.LinByteArrayTag;
import org.enginehub.linbus.tree.LinByteTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinEndTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinIntArrayTag;
import org.enginehub.linbus.tree.LinIntTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinLongArrayTag;
import org.enginehub.linbus.tree.LinLongTag;
import org.enginehub.linbus.tree.LinShortTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import org.enginehub.linbus.tree.LinTagType;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -145,6 +153,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -159,20 +168,21 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> { public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> {
private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
private final Field serverWorldsField; private final Field serverWorldsField;
private final Method getChunkFutureMethod; private final Method getChunkFutureMethod;
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -182,8 +192,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
CraftServer.class.cast(Bukkit.getServer()); CraftServer.class.cast(Bukkit.getServer());
int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion();
if (dataVersion != 3463 && dataVersion != 3465) { if (dataVersion != 3698 && dataVersion != 3700) {
throw new UnsupportedClassVersionError("Not 1.20(.1)!"); throw new UnsupportedClassVersionError("Not 1.20.(3/4)!");
} }
serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField = CraftServer.class.getDeclaredField("worlds");
@ -281,12 +291,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static Block getBlockFromType(BlockType blockType) { private static Block getBlockFromType(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id()));
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.getId()));
} }
private static Item getItemFromType(ItemType itemType) { private static Item getItemFromType(ItemType itemType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.getId())); return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id()));
} }
@Override @Override
@ -306,6 +315,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId);
} }
public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
int internalId = Block.getId(blockState);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
state = BukkitAdapter.adapt(CraftBlockData.createData(blockState));
}
return state;
}
public BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId);
}
@Override @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -319,14 +351,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData); return adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
} }
@Override @Override
@ -346,21 +371,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockEntity te = chunk.getBlockEntity(blockPos); BlockEntity te = chunk.getBlockEntity(blockPos);
if (te != null) { if (te != null) {
net.minecraft.nbt.CompoundTag tag = te.saveWithId(); net.minecraft.nbt.CompoundTag tag = te.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
return state.toBaseBlock(); return state.toBaseBlock();
} }
/*
@Override
public boolean hasCustomBiomeSupport() {
return true;
}
*/
private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>(); private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>();
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
/* @Override @Override
public BiomeType getBiome(Location location) { public BiomeType getBiome(Location location) {
checkNotNull(location); checkNotNull(location);
@ -387,14 +407,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.getId()))))); chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id())))));
chunk.setUnsaved(true); chunk.setUnsaved(true);
}*/ }
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this, return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
new WeakReference<>(((CraftWorld) world).getHandle()));
} }
private static net.minecraft.core.Direction adapt(Direction face) { private static net.minecraft.core.Direction adapt(Direction face) {
@ -465,7 +484,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
readEntityIntoTag(mcEntity, tag); readEntityIntoTag(mcEntity, tag);
return new BaseEntity( return new BaseEntity(
com.sk89q.worldedit.world.entity.EntityTypes.get(id), com.sk89q.worldedit.world.entity.EntityTypes.get(id),
LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag))
); );
} }
@ -478,12 +497,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
CraftWorld craftWorld = ((CraftWorld) location.getWorld()); CraftWorld craftWorld = ((CraftWorld) location.getWorld());
ServerLevel worldServer = craftWorld.getHandle(); ServerLevel worldServer = craftWorld.getHandle();
Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle());
if (createdEntity != null) { if (createdEntity != null) {
CompoundBinaryTag nativeTag = state.getNbt(); LinCompoundTag nativeTag = state.getNbt();
if (nativeTag != null) { if (nativeTag != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag);
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
@ -531,21 +550,39 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
.newBuilder()
.build(new CacheLoader<>() {
@Override @Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) { } else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(), return new DirectionalProperty(
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); state.getName(),
new ArrayList<>((List<Direction>) state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName()
.toUpperCase(Locale.ROOT)))
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(), return new EnumProperty(
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else { } else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
} }
} }
}); });
@ -565,27 +602,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) {
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
new StructureBlockEntity( new StructureBlockEntity(
new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), new BlockPos(pos.x(), pos.y(), pos.z()),
Blocks.STRUCTURE_BLOCK.defaultBlockState() Blocks.STRUCTURE_BLOCK.defaultBlockState()
), ),
__ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData)
)); ));
} }
/*@Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
new StructureBlockEntity(
new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()),
Blocks.STRUCTURE_BLOCK.defaultBlockState()
),
__ -> (net.minecraft.nbt.CompoundTag) fromNative(nbtData)
));
}*/
@Override @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
@ -596,7 +622,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().getId())), DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount() item.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
@ -607,7 +633,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag()));
return weStack; return weStack;
} }
@ -629,10 +655,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; return false;
} }
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.getBlockX(), position.getBlockY(), position.getBlockZ(), fakePlayer.absMoveTo(position.x(), position.y(), position.z(),
(float) face.toVector().toYaw(), (float) face.toVector().toPitch()); (float) face.toVector().toYaw(), (float) face.toVector().toPitch());
final BlockPos blockPos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
final net.minecraft.core.Direction enumFacing = adapt(face); final net.minecraft.core.Direction enumFacing = adapt(face);
BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false); BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false);
@ -650,14 +676,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.getX(), position.getY(), position.getZ())); return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
} }
@Override @Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) {
try { try {
doRegen(bukkitWorld, region, extent, options); doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) { } catch (Exception e) {
@ -667,7 +693,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true; return true;
} }
private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
Environment env = bukkitWorld.getEnvironment(); Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator(); ChunkGenerator gen = bukkitWorld.getGenerator();
@ -695,6 +721,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
levelProperties.settings.getDataConfiguration() levelProperties.settings.getDataConfiguration()
); );
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty = PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld() levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT ? PrimaryLevelData.SpecialWorldProperty.FLAT
@ -731,7 +758,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer()); Map<String, World> map = (Map<String, World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -774,7 +801,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
for (BlockVector3 vec : region) { for (BlockVector3 vec : region) {
BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); BlockPos pos = new BlockPos(vec.x(), vec.y(), vec.z());
ChunkAccess chunk = chunks.get(new ChunkPos(pos)); ChunkAccess chunk = chunks.get(new ChunkPos(pos));
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos);
int internalId = Block.getId(blockData); int internalId = Block.getId(blockData);
@ -783,11 +810,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockEntity blockEntity = chunk.getBlockEntity(pos); BlockEntity blockEntity = chunk.getBlockEntity(pos);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
extent.setBlock(vec, state.toBaseBlock()); extent.setBlock(vec, state.toBaseBlock());
if (options.shouldRegenBiomes()) { if (options.shouldRegenBiomes()) {
Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); Biome origBiome = chunk.getNoiseBiome(vec.x(), vec.y(), vec.z()).value();
BiomeType adaptedBiome = adapt(serverWorld, origBiome); BiomeType adaptedBiome = adapt(serverWorld, origBiome);
if (adaptedBiome != null) { if (adaptedBiome != null) {
extent.setBiome(vec, adaptedBiome); extent.setBiome(vec, adaptedBiome);
@ -806,7 +833,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
//noinspection unchecked //noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>) ((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null)) .thenApply(either -> either.left().orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
@ -843,10 +870,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
if (entity instanceof Clearable) { if (entity instanceof Clearable) {
((Clearable) entity).clearContent(); ((Clearable) entity).clearContent();
return true; return true;
@ -854,7 +881,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; return false;
} }
/*@Override @Override
public void initializeRegistries() { public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes // Biomes
@ -863,7 +890,35 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
} }
} }
}*
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
@Override
public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
List<ChunkAccess> nativeChunks = chunks instanceof Collection<BlockVector2> chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList();
for (BlockVector2 chunk : chunks) {
nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false));
}
originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that is less likely to break // Code that is less likely to break
@ -877,51 +932,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @return native WorldEdit NBT structure * @return native WorldEdit NBT structure
*/ */
@Override @Override
public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { public LinTag<?> toNativeLin(net.minecraft.nbt.Tag foreign) {
if (foreign == null) { if (foreign == null) {
return null; return null;
} }
if (foreign instanceof net.minecraft.nbt.CompoundTag) { if (foreign instanceof net.minecraft.nbt.CompoundTag) {
Map<String, BinaryTag> values = new HashMap<>(); Map<String, LinTag<?>> values = new HashMap<>();
Set<String> foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); Set<String> foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys();
for (String str : foreignKeys) { for (String str : foreignKeys) {
net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str);
values.put(str, toNativeBinary(base)); values.put(str, toNativeLin(base));
} }
return CompoundBinaryTag.from(values); return LinCompoundTag.of(values);
} else if (foreign instanceof net.minecraft.nbt.ByteTag) { } else if (foreign instanceof net.minecraft.nbt.ByteTag) {
return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte());
} else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) {
return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray());
} else if (foreign instanceof net.minecraft.nbt.DoubleTag) { } else if (foreign instanceof net.minecraft.nbt.DoubleTag) {
return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble());
} else if (foreign instanceof net.minecraft.nbt.FloatTag) { } else if (foreign instanceof net.minecraft.nbt.FloatTag) {
return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat());
} else if (foreign instanceof net.minecraft.nbt.IntTag) { } else if (foreign instanceof net.minecraft.nbt.IntTag) {
return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt());
} else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) {
return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray());
} else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) {
return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray());
} else if (foreign instanceof net.minecraft.nbt.ListTag) { } else if (foreign instanceof net.minecraft.nbt.ListTag) {
try { try {
return toNativeList((net.minecraft.nbt.ListTag) foreign); return toNativeLinList((net.minecraft.nbt.ListTag) foreign);
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
return ListBinaryTag.empty();
} }
} else if (foreign instanceof net.minecraft.nbt.LongTag) { } else if (foreign instanceof net.minecraft.nbt.LongTag) {
return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong());
} else if (foreign instanceof net.minecraft.nbt.ShortTag) { } else if (foreign instanceof net.minecraft.nbt.ShortTag) {
return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort());
} else if (foreign instanceof net.minecraft.nbt.StringTag) { } else if (foreign instanceof net.minecraft.nbt.StringTag) {
return StringBinaryTag.of(foreign.getAsString()); return LinStringTag.of(foreign.getAsString());
} else if (foreign instanceof net.minecraft.nbt.EndTag) { } else if (foreign instanceof net.minecraft.nbt.EndTag) {
return EndBinaryTag.get(); return LinEndTag.instance();
} else {
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
} }
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
} }
/** /**
@ -932,14 +985,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @throws SecurityException on error * @throws SecurityException on error
* @throws IllegalArgumentException on error * @throws IllegalArgumentException on error
*/ */
private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { private LinListTag<?> toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException {
ListBinaryTag.Builder values = ListBinaryTag.builder(); LinListTag.Builder<LinTag<?>> builder = LinListTag.builder(
LinTagType.fromId(LinTagId.fromId(foreign.getElementType()))
);
for (net.minecraft.nbt.Tag tag : foreign) { for (net.minecraft.nbt.Tag tag : foreign) {
values.add(toNativeBinary(tag)); builder.add(toNativeLin(tag));
} }
return values.build(); return builder.build();
} }
/** /**
@ -949,44 +1004,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @return non-native structure * @return non-native structure
*/ */
@Override @Override
public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { public net.minecraft.nbt.Tag fromNativeLin(LinTag<?> foreign) {
if (foreign == null) { if (foreign == null) {
return null; return null;
} }
if (foreign instanceof CompoundBinaryTag) { if (foreign instanceof LinCompoundTag compoundTag) {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
for (String key : ((CompoundBinaryTag) foreign).keySet()) { for (var entry : compoundTag.value().entrySet()) {
tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); tag.put(entry.getKey(), fromNativeLin(entry.getValue()));
} }
return tag; return tag;
} else if (foreign instanceof ByteBinaryTag) { } else if (foreign instanceof LinByteTag byteTag) {
return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte());
} else if (foreign instanceof ByteArrayBinaryTag) { } else if (foreign instanceof LinByteArrayTag byteArrayTag) {
return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value());
} else if (foreign instanceof DoubleBinaryTag) { } else if (foreign instanceof LinDoubleTag doubleTag) {
return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble());
} else if (foreign instanceof FloatBinaryTag) { } else if (foreign instanceof LinFloatTag floatTag) {
return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat());
} else if (foreign instanceof IntBinaryTag) { } else if (foreign instanceof LinIntTag intTag) {
return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt());
} else if (foreign instanceof IntArrayBinaryTag) { } else if (foreign instanceof LinIntArrayTag intArrayTag) {
return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.IntArrayTag(intArrayTag.value());
} else if (foreign instanceof LongArrayBinaryTag) { } else if (foreign instanceof LinLongArrayTag longArrayTag) {
return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.LongArrayTag(longArrayTag.value());
} else if (foreign instanceof ListBinaryTag) { } else if (foreign instanceof LinListTag<?> listTag) {
net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag();
ListBinaryTag foreignList = (ListBinaryTag) foreign; for (var t : listTag.value()) {
for (BinaryTag t : foreignList) { tag.add(fromNativeLin(t));
tag.add(fromNativeBinary(t));
} }
return tag; return tag;
} else if (foreign instanceof LongBinaryTag) { } else if (foreign instanceof LinLongTag longTag) {
return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong());
} else if (foreign instanceof ShortBinaryTag) { } else if (foreign instanceof LinShortTag shortTag) {
return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort());
} else if (foreign instanceof StringBinaryTag) { } else if (foreign instanceof LinStringTag stringTag) {
return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); return net.minecraft.nbt.StringTag.valueOf(stringTag.value());
} else if (foreign instanceof EndBinaryTag) { } else if (foreign instanceof LinEndTag) {
return net.minecraft.nbt.EndTag.INSTANCE; return net.minecraft.nbt.EndTag.INSTANCE;
} else { } else {
throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName());
@ -1025,7 +1079,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
WatchdogThread.tick(); WatchdogThread.tick();
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); logger.log(Level.WARNING, "Failed to tick watchdog", e);
} }
} }
} }
@ -1037,7 +1091,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server; this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField( Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah") Refraction.pickName("nextTickTime", "ag")
); );
if (tickField.getType() != long.class) { if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -35,7 +35,6 @@ import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic; import com.mojang.serialization.Dynamic;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@ -48,7 +47,9 @@ import net.minecraft.util.datafix.fixes.References;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
@ -62,7 +63,6 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.stream.Collectors; 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) * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2)
@ -76,18 +76,17 @@ import javax.annotation.Nullable;
* receive the source version in the compound * receive the source version in the compound
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer {
//FAWE start - BinaryTag
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T fixUp(FixType<T> type, T original, int srcVer) { public <T> T fixUp(FixType<T> type, T original, int srcVer) {
if (type == FixTypes.CHUNK) { if (type == FixTypes.CHUNK) {
return (T) fixChunk((CompoundBinaryTag) original, srcVer); return (T) fixChunk((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_ENTITY) { } else if (type == FixTypes.BLOCK_ENTITY) {
return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); return (T) fixBlockEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.ENTITY) { } else if (type == FixTypes.ENTITY) {
return (T) fixEntity((CompoundBinaryTag) original, srcVer); return (T) fixEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_STATE) { } else if (type == FixTypes.BLOCK_STATE) {
return (T) fixBlockState((String) original, srcVer); return (T) fixBlockState((String) original, srcVer);
} else if (type == FixTypes.ITEM_TYPE) { } else if (type == FixTypes.ITEM_TYPE) {
@ -98,24 +97,23 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return original; return original;
} }
private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
//FAWE end
private String fixBlockState(String blockState, int srcVer) { private String fixBlockState(String blockState, int srcVer) {
net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState);
@ -173,7 +171,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private static final NbtOps OPS_NBT = NbtOps.INSTANCE; private static final NbtOps OPS_NBT = NbtOps.INSTANCE;
private static final int LEGACY_VERSION = 1343; private static final int LEGACY_VERSION = 1343;
private static int DATA_VERSION; private static int DATA_VERSION;
static PaperweightDataConverters INSTANCE; public static PaperweightDataConverters INSTANCE;
private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class);
private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class);
@ -204,7 +202,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
} }
} }
PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) {
super(dataVersion); super(dataVersion);
DATA_VERSION = dataVersion; DATA_VERSION = dataVersion;
INSTANCE = this; INSTANCE = this;
@ -234,7 +232,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
} }
@Override @Override
public <T> Dynamic<T> update(TypeReference type, Dynamic<T> dynamic, int sourceVer, int targetVer) { public <T> Dynamic<T> update(TypeReference type, Dynamic<T> dynamic, int sourceVer, int targetVer) {
LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName());
if (sourceVer < LEGACY_VERSION && legacyType != null) { if (sourceVer < LEGACY_VERSION && legacyType != null) {

Datei anzeigen

@ -17,17 +17,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component; 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.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat; import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity; 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.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
@ -38,9 +40,12 @@ import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer { 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 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) { PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO);
} }
@Override @Override
@ -67,7 +72,7 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void updateOptions(ServerboundClientInformationPacket packet) { public void updateOptions(ClientInformation clientOptions) {
} }
@Override @Override
@ -88,6 +93,6 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void openTextEdit(SignBlockEntity sign) { public void openTextEdit(SignBlockEntity sign, boolean front) {
} }
} }

Datei anzeigen

@ -17,27 +17,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -101,9 +104,16 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) {
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false; return false;
} }
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override @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) {
@ -114,7 +124,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public boolean isChunkTicking(LevelChunk chunk) { public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -144,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -153,8 +169,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @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(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();

Datei anzeigen

@ -1,32 +1,27 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
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_19_R3.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; 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.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 net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import javax.annotation.Nullable;
public class PaperweightBlockMaterial implements BlockMaterial { public class PaperweightBlockMaterial implements BlockMaterial {
private final Block block; private final Block block;
private final BlockState blockState; private final BlockState blockState;
private final Material material;
private final boolean isTranslucent;
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
private final int opacity; private final int opacity;
private final CompoundTag tile; private final FaweCompoundTag tile;
public PaperweightBlockMaterial(Block block) { public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState()); this(block, block.defaultBlockState());
@ -35,14 +30,8 @@ public class PaperweightBlockMaterial implements BlockMaterial {
public PaperweightBlockMaterial(Block block, BlockState blockState) { public PaperweightBlockMaterial(Block block, BlockState blockState) {
this.block = block; this.block = block;
this.blockState = blockState; this.blockState = blockState;
this.material = blockState.getMaterial();
this.craftBlockData = CraftBlockData.fromData(blockState); this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial(); 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); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
BlockPos.ZERO, BlockPos.ZERO,
@ -50,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
); );
tile = tileEntity == null tile = tileEntity == null
? null ? null
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
} }
public Block getBlock() { public Block getBlock() {
@ -65,10 +54,6 @@ public class PaperweightBlockMaterial implements BlockMaterial {
return craftBlockData; return craftBlockData;
} }
public Material getMaterial() {
return material;
}
@Override @Override
public boolean isAir() { public boolean isAir() {
return blockState.isAir(); return blockState.isAir();
@ -81,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isOpaque() { public boolean isOpaque() {
return material.isSolidBlocking(); return blockState.canOcclude();
} }
@Override @Override
@ -91,12 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isLiquid() { public boolean isLiquid() {
return material.isLiquid(); return !blockState.getFluidState().is(Fluids.EMPTY);
} }
@Override @Override
public boolean isSolid() { public boolean isSolid() {
return material.isSolid(); // No access to world -> EmptyBlockGetter
return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
} }
@Override @Override
@ -126,12 +112,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isFragileWhenPushed() { public boolean isFragileWhenPushed() {
return material.getPushReaction() == PushReaction.DESTROY; return blockState.getPistonPushReaction() == PushReaction.DESTROY;
} }
@Override @Override
public boolean isUnpushable() { public boolean isUnpushable() {
return material.getPushReaction() == PushReaction.BLOCK; return blockState.getPistonPushReaction() == PushReaction.BLOCK;
} }
@Override @Override
@ -139,14 +125,15 @@ public class PaperweightBlockMaterial implements BlockMaterial {
return block.isRandomlyTicking(blockState); return block.isRandomlyTicking(blockState);
} }
@SuppressWarnings("deprecation")
@Override @Override
public boolean isMovementBlocker() { public boolean isMovementBlocker() {
return material.isSolid(); return blockState.blocksMotion();
} }
@Override @Override
public boolean isBurnable() { public boolean isBurnable() {
return material.isFlammable(); return craftMaterial.isBurnable();
} }
@Override @Override
@ -157,12 +144,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isReplacedDuringPlacement() { public boolean isReplacedDuringPlacement() {
return material.isReplaceable(); return blockState.canBeReplaced();
} }
@Override @Override
public boolean isTranslucent() { public boolean isTranslucent() {
return isTranslucent; return !blockState.canOcclude();
} }
@Override @Override
@ -176,14 +163,14 @@ public class PaperweightBlockMaterial implements BlockMaterial {
} }
@Override @Override
public CompoundTag getDefaultTile() { public @Nullable FaweCompoundTag defaultTile() {
return tile; return tile;
} }
@Override @Override
public int getMapColor() { public int getMapColor() {
// rgb field // rgb field
return material.getColor().col; return block.defaultMapColor().col;
} }
} }

Datei anzeigen

@ -1,28 +1,24 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitAdapter; 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.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.regen.PaperweightRegen;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -38,11 +34,7 @@ import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; 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.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -77,19 +69,20 @@ import net.minecraft.world.level.chunk.LevelChunk;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -105,14 +98,14 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static net.minecraft.core.registries.Registries.BIOME; import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.Tag, ServerLevel> {
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
@ -124,18 +117,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
} }
private final PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new PaperweightAdapter(); super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter());
}
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
return blockEntity -> FaweCompoundTag.of(
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId())
);
} }
@Nullable @Nullable
@ -248,11 +239,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -268,12 +258,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseBlock getFullBlock(final Location location) { public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -288,7 +277,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
} }
@ -302,10 +291,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess( return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world)));
this,
new WeakReference<>(((CraftWorld) world).getHandle())
);
} }
@Override @Override
@ -319,14 +305,14 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { Supplier<LinCompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, LinTag<?>> tags = NbtUtils.getLinCompoundTagValues(tag);
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", LinStringTag.of(id));
return CompoundBinaryTag.from(tags); return LinCompoundTag.of(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -450,7 +436,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { 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()); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && wasAccessibleSinceLastSave(map)) { if (map != null && wasAccessibleSinceLastSave(map)) {
boolean flag = false; boolean flag = false;
@ -488,8 +474,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess( return blockState1.hasPostProcess(
((CraftWorld) world).getHandle(), getServerLevel(world),
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z())
); );
} }
@ -497,7 +483,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM)
.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), .get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount() baseItemStack.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
@ -505,54 +491,33 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
@Override @Override
public boolean generateTree( protected void preCaptureStates(final ServerLevel serverLevel) {
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<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
} }
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally { @Override
protected List<org.bukkit.block.BlockState> getCapturedBlockStatesCopy(final ServerLevel serverLevel) {
return new ArrayList<>(serverLevel.capturedBlockStates.values());
}
@Override
protected void postCaptureBlockStates(final ServerLevel serverLevel) {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
} }
});
if (placed == null || placed.isEmpty()) { @Override
return false; protected ServerLevel getServerLevel(final World world) {
} return ((CraftWorld) world).getHandle();
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;
} }
@Override @Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag())));
return weStack; return weStack;
} }
@ -585,7 +550,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
.getServer() .getServer()
.registryAccess() .registryAccess()
.registryOrThrow(BIOME); .registryOrThrow(BIOME);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id());
Biome biome = registry.get(resourceLocation); Biome biome = registry.get(resourceLocation);
return registry.getId(biome); return registry.getId(biome);
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.math.IntPair;
@ -9,21 +9,21 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -132,14 +132,14 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
@Override @Override
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) {
// We will assume that the tile entity was created for us, // We will assume that the tile entity was created for us,
// though we do not do this on the other versions // though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) { if (blockEntity == null) {
return false; return false;
} }
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag);
blockEntity.load((CompoundTag) nativeTag); blockEntity.load((CompoundTag) nativeTag);
return true; return true;
} }
@ -157,7 +157,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
@Override @Override
public boolean isChunkTicking(LevelChunk levelChunk) { public boolean isChunkTicking(LevelChunk levelChunk) {
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,
@ -246,7 +252,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };
@ -262,7 +268,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -34,6 +31,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
@ -58,14 +56,22 @@ import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTagType;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.AbstractSet; import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -75,12 +81,13 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static net.minecraft.core.registries.Registries.BIOME; import static net.minecraft.core.registries.Registries.BIOME;
@ -89,29 +96,34 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
private static final Function<BlockEntity, CompoundTag> nmsTile2We = public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); .getInstance()
.getBukkitImplAdapter()).blockEntityToCompoundTag();
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
.getInstance() .getInstance()
.getBukkitImplAdapter()); .getBukkitImplAdapter());
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
private final ReentrantLock callLock = new ReentrantLock();
private final ServerLevel serverLevel; private final ServerLevel serverLevel;
private final int chunkX; private final int chunkX;
private final int chunkZ; private final int chunkZ;
private final IntPair chunkPos;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
private final int minSectionPosition; private final int minSectionPosition;
private final int maxSectionPosition; private final int maxSectionPosition;
private final Registry<Biome> biomeRegistry; private final Registry<Biome> biomeRegistry;
private final IdMap<Holder<Biome>> biomeHolderIdMap; private final IdMap<Holder<Biome>> biomeHolderIdMap;
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
private final Object sendLock = new Object();
private LevelChunkSection[] sections; private LevelChunkSection[] sections;
private LevelChunk levelChunk; private LevelChunk levelChunk;
private DataLayer[] blockLight; private DataLayer[] blockLight;
private DataLayer[] skyLight; private DataLayer[] skyLight;
private boolean createCopy = false; private boolean createCopy = false;
private PaperweightGetBlocks_Copy copy = null;
private boolean forceLoadSections = true; private boolean forceLoadSections = true;
private boolean lightUpdate = false; private boolean lightUpdate = false;
private int copyKey = 0;
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ); this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -130,6 +142,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.blockLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()];
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
this.chunkPos = new IntPair(chunkX, chunkZ);
} }
public int getChunkX() { public int getChunkX() {
@ -146,13 +159,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
}
this.createCopy = createCopy; this.createCopy = createCopy;
// Increment regardless of whether copy will be created or not to return null from getCopy()
return ++this.copyKey;
} }
@Override @Override
public IChunkGet getCopy() { public IChunkGet getCopy(final int key) {
return copy; return copies.remove(key);
}
@Override
public void lockCall() {
this.callLock.lock();
}
@Override
public void unlockCall() {
this.callLock.unlock();
} }
@Override @Override
@ -236,23 +264,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getTile(int x, int y, int z) { public FaweCompoundTag tile(final int x, final int y, final int z) {
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
chunkX << 4), y, (z & 15) + ( chunkX << 4), y, (z & 15) + (
chunkZ << 4))); chunkZ << 4)));
if (blockEntity == null) { if (blockEntity == null) {
return null; return null;
} }
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); return NMS_TO_TILE.apply(blockEntity);
} }
@Override @Override
public Map<BlockVector3, CompoundTag> getTiles() { public Map<BlockVector3, FaweCompoundTag> tiles() {
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities(); Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
if (nmsTiles.isEmpty()) { if (nmsTiles.isEmpty()) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
} }
@Override @Override
@ -272,8 +301,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
LightLayer.BLOCK, LightLayer.BLOCK,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
skyLight[alayer] = dataLayer; skyLight[alayer] = dataLayer;
@ -300,7 +328,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
Arrays.fill(LAYER_COUNT, (byte) 15); Arrays.fill(LAYER_COUNT, (byte) 15);
dataLayer = new DataLayer(LAYER_COUNT); dataLayer = new DataLayer(LAYER_COUNT);
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos,
dataLayer, true dataLayer
); );
} }
blockLight[alayer] = dataLayer; blockLight[alayer] = dataLayer;
@ -316,14 +344,22 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
Entity entity = serverLevel.getEntity(uuid); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
Entity entity = null;
for (Entity e : entities) {
if (e.getUUID().equals(uuid)) {
entity = e;
break;
}
}
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
} }
for (CompoundTag tag : getEntities()) { for (FaweCompoundTag tag : entities()) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -331,14 +367,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
ensureLoaded(serverLevel, chunkX, chunkZ); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
if (entities.isEmpty()) { if (entities.isEmpty()) {
return Collections.emptySet(); return Collections.emptyList();
} }
int size = entities.size(); int size = entities.size();
return new AbstractSet<>() { return new AbstractCollection<>() {
@Override @Override
public int size() { public int size() {
return size; return size;
@ -351,10 +387,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public boolean contains(Object get) { public boolean contains(Object get) {
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof FaweCompoundTag getTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); UUID getUUID = NbtUtils.uuid(getTag);
for (Entity entity : entities) { for (Entity entity : entities) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
@ -366,12 +402,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Nonnull @Nonnull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<FaweCompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
input.save(tag); input.save(tag);
return (CompoundTag) adapter.toNative(tag); return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
}).collect(Collectors.toList()); })::iterator;
return result.iterator(); return result.iterator();
} }
}; };
@ -388,12 +424,19 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
}
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
if (createCopy) {
if (copies.containsKey(copyKey)) {
throw new IllegalStateException("Copy key already used.");
}
copies.put(copyKey, copy);
}
try { try {
ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
// Remove existing tiles. Create a copy so that we can remove blocks // Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
List<BlockEntity> beacons = null; List<BlockEntity> beacons = null;
@ -465,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -482,7 +527,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (paletteBiomes != null) {
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
}
} }
} }
} }
@ -524,13 +576,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance() PalettedContainer.Strategy.SECTION_BIOMES
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
@ -540,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -596,16 +645,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
this::loadPrivately, this::loadPrivately,
setArr, setArr,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
); );
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
existingSection, existingSection,
newSection, newSection,
@ -679,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) { for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.getEntities().get(uuid); Entity entity = serverLevel.getEntities().get(uuid);
if (entity != null) { if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
@ -691,48 +741,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
}; };
} }
Set<CompoundTag> entities = set.getEntities(); Collection<FaweCompoundTag> entities = set.entities();
if (entities != null && !entities.isEmpty()) { if (entities != null && !entities.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[2]; syncTasks = new Runnable[2];
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); Iterator<FaweCompoundTag> iterator = entities.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final CompoundTag nativeTag = iterator.next(); final FaweCompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final LinCompoundTag linTag = nativeTag.linTag();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
if (idTag == null || posTag == null || rotTag == null) { if (idTag == null || posTag == null || rotTag == null) {
LOGGER.error("Unknown entity tag: {}", nativeTag); LOGGER.error("Unknown entity tag: {}", nativeTag);
continue; continue;
} }
final double x = posTag.getDouble(0); final double x = posTag.get(0).valueAsDouble();
final double y = posTag.getDouble(1); final double y = posTag.get(1).valueAsDouble();
final double z = posTag.getDouble(2); final double z = posTag.get(2).valueAsDouble();
final float yaw = rotTag.getFloat(0); final float yaw = rotTag.get(0).valueAsFloat();
final float pitch = rotTag.getFloat(1); final float pitch = rotTag.get(1).valueAsFloat();
final String id = idTag.getValue(); final String id = idTag.value();
EntityType<?> type = EntityType.byString(id).orElse(null); EntityType<?> type = EntityType.byString(id).orElse(null);
if (type != null) { if (type != null) {
Entity entity = type.create(nmsWorld); Entity entity = type.create(serverLevel);
if (entity != null) { if (entity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag);
nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); entity.setUUID(NbtUtils.uuid(nativeTag));
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn( LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`", "Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id, id,
nmsWorld.getWorld().getName(), serverLevel.getWorld().getName(),
x, x,
y, y,
z z
@ -747,30 +796,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
// set tiles // set tiles
Map<BlockVector3, CompoundTag> tiles = set.getTiles(); Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
if (tiles != null && !tiles.isEmpty()) { if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[1]; syncTasks = new Runnable[1];
} }
syncTasks[0] = () -> { syncTasks[0] = () -> {
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) { for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue(); final FaweCompoundTag nativeTag = entry.getValue();
final BlockVector3 blockHash = entry.getKey(); final BlockVector3 blockHash = entry.getKey();
final int x = blockHash.getX() + bx; final int x = blockHash.x() + bx;
final int y = blockHash.getY(); final int y = blockHash.y();
final int z = blockHash.getZ() + bz; final int z = blockHash.z() + bz;
final BlockPos pos = new BlockPos(x, y, z); final BlockPos pos = new BlockPos(x, y, z);
synchronized (nmsWorld) { synchronized (serverLevel) {
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
if (tileEntity == null || tileEntity.isRemoved()) { if (tileEntity == null || tileEntity.isRemoved()) {
nmsWorld.removeBlockEntity(pos); serverLevel.removeBlockEntity(pos);
tileEntity = nmsWorld.getBlockEntity(pos); tileEntity = serverLevel.getBlockEntity(pos);
} }
if (tileEntity != null) { if (tileEntity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
nativeTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
@ -786,15 +834,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
callback = null; callback = null;
} else { } else {
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
boolean finalLightUpdate = lightUpdate;
callback = () -> { callback = () -> {
// Set Modified // Set Modified
nmsChunk.setLightCorrect(true); // Set Modified nmsChunk.setLightCorrect(true); // Set Modified
nmsChunk.mustNotSave = false; nmsChunk.mustNotSave = false;
nmsChunk.setUnsaved(true); nmsChunk.setUnsaved(true);
// send to player // send to player
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
this.send(finalMask, finalLightUpdate); this.send();
} }
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); finalizer.run();
@ -816,7 +863,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -882,9 +929,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (super.sections[layer] != null) { if (super.sections[layer] != null) {
synchronized (super.sectionLocks[layer]) { synchronized (super.sectionLocks[layer]) {
if (super.sections[layer].isFull() && super.blocks[layer] != null) { if (super.sections[layer].isFull() && super.blocks[layer] != null) {
char[] blocks = new char[4096]; return super.blocks[layer];
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
return blocks;
} }
} }
} }
@ -892,8 +937,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send() {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
} }
/** /**
@ -1004,9 +1049,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
public LevelChunkSection[] getSections(boolean force) { public LevelChunkSection[] getSections(boolean force) {
force &= forceLoadSections; force &= forceLoadSections;
sectionLock.readLock().lock();
LevelChunkSection[] tmp = sections; LevelChunkSection[] tmp = sections;
sectionLock.readLock().unlock();
if (tmp == null || force) { if (tmp == null || force) {
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
@ -1052,8 +1095,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
lightLayer, lightLayer,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
synchronized (dataLayer) { synchronized (dataLayer) {
@ -1076,41 +1118,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> 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; BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return biomeData; return null;
} }
PalettedContainer<Holder<Biome>> biomeData = data.recreate();
for (int y = 0, index = 0; y < 4; y++) { for (int y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = sectionBiomes[index]; BiomeType biomeType = sectionBiomes[index];
if (biomeType == null) { if (biomeType == null) {
continue; biomeData.set(x, y, z, data.get(x, y, z));
} } else {
biomeData.set( biomeData.set(
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }
} }
}
return biomeData; return biomeData;
} }

Datei anzeigen

@ -1,21 +1,22 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.util.NbtUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
@ -24,8 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -37,14 +41,14 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>(); private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>(); private final Set<FaweCompoundTag> entities = new HashSet<>();
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; final ServerLevel serverLevel;
final LevelChunk levelChunk; final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null; private Holder<Biome>[][] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk; this.levelChunk = levelChunk;
@ -55,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
protected void storeTile(BlockEntity blockEntity) { protected void storeTile(BlockEntity blockEntity) {
@SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
tiles.put( tiles.put(
BlockVector3.at( BlockVector3.at(
blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ() blockEntity.getBlockPos().getZ()
), ),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId()))
); );
} }
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); @SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag)); entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
return this.entities; return this.entities;
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
for (CompoundTag tag : entities) { for (FaweCompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -105,7 +100,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -142,7 +138,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
return PaperweightPlatformAdapter.adapt(biome, serverLevel); return PaperweightPlatformAdapter.adapt(biome, serverLevel);
} }
@ -171,10 +167,25 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) { protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) { if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()]; biomes = new Holder[getSectionCount()][];
}
if (biomes[layer] == null) {
biomes[layer] = new Holder[64];
} }
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomes[layer] = palettedContainer.copy(); if (PaperLib.isPaper()) {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
}
} else {
try {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} else { } else {
LOGGER.error( LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}", "Cannot correctly save biomes to history. Expected class type {} but got {}",
@ -187,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)]; BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z); return state.toBaseBlock((IBlocks) this, x, y, z);
} }
@Override @Override
@ -199,6 +210,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public char[] load(int layer) { public char[] load(int layer) {
layer -= getMinSectionPosition(); layer -= getMinSectionPosition();
if (blocks[layer] == null) {
blocks[layer] = new char[4096];
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
}
return blocks[layer]; return blocks[layer];
} }
@ -213,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return BlockTypesCache.states[get(x, y, z)]; return BlockTypesCache.states[get(x, y, z)];
} }
@Override
public Map<BlockVector3, FaweCompoundTag> tiles() {
return tiles;
}
@Override
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@Override @Override
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
return 0; return 0;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.destroystokyo.paper.util.maplist.EntityList; import com.destroystokyo.paper.util.maplist.EntityList;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
@ -26,6 +26,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -44,6 +45,7 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity; 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.ChunkStatus;
import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette; import net.minecraft.world.level.chunk.HashMapPalette;
@ -56,13 +58,13 @@ import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -82,6 +84,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.function.Function; import java.util.function.Function;
import static java.lang.invoke.MethodType.methodType;
import static net.minecraft.core.registries.Registries.BIOME; import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightPlatformAdapter extends NMSAdapter { public final class PaperweightPlatformAdapter extends NMSAdapter {
@ -95,22 +98,22 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector; private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock; private static final Field fieldLock;
private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity; 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 Field fieldRemove;
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
@ -120,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static Field LEVEL_CHUNK_ENTITIES; private static Field LEVEL_CHUNK_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER; private static Field SERVER_LEVEL_ENTITY_MANAGER;
static final MethodHandle PALETTED_CONTAINER_GET;
static { static {
final MethodHandles.Lookup lookup = MethodHandles.lookup(); final MethodHandles.Lookup lookup = MethodHandles.lookup();
try { try {
@ -135,12 +140,19 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true); fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g"));
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); Field tmpFieldBiomes;
fieldNonEmptyBlockCount.setAccessible(true); try {
// It seems to actually be biomes, but is apparently obfuscated to "i"
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
} catch (NoSuchFieldException ignored) {
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i");
}
fieldBiomes = tmpFieldBiomes;
fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -149,20 +161,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
getVisibleChunkIfPresent.setAccessible(true); getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) { if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetector.setAccessible(true);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); fieldLock.setAccessible(true);
} else { } else {
// in paper, the used methods are synchronized properly // in paper, the used methods are synchronized properly
fieldThreadingDetector = null; fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null; fieldLock = null;
fieldLockOffset = -1;
} }
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
@ -185,12 +192,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q"));
fieldRemove.setAccessible(true); fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
boolean chunkRewrite; boolean chunkRewrite;
try { try {
ServerLevel.class.getDeclaredMethod("getEntityLookup"); ServerLevel.class.getDeclaredMethod("getEntityLookup");
@ -208,29 +209,48 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
try { try {
// Non-Paper // Non-Paper
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "L")); SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true); SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} catch (NoSuchFieldException ignored) { } catch (NoSuchFieldException ignored) {
} }
POST_CHUNK_REWRITE = chunkRewrite; POST_CHUNK_REWRITE = chunkRewrite;
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
Refraction.pickName("get", "a"),
int.class
);
palettedContaienrGet.setAccessible(true);
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
} catch (RuntimeException | Error e) { } catch (RuntimeException | Error e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(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( static boolean setSectionAtomic(
String worldName,
IntPair pair,
LevelChunkSection[] sections, LevelChunkSection[] sections,
LevelChunkSection expected, LevelChunkSection expected,
LevelChunkSection value, LevelChunkSection value,
int layer int layer
) { ) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
} }
// There is no point in having a functional semaphore for paper servers. // There is no point in having a functional semaphore for paper servers.
@ -243,19 +263,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks);
blocks,
fieldThreadingDetectorOffset
);
synchronized (currentThreadingDetector) { synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) { if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore; return delegateSemaphore;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); fieldLock.set(currentThreadingDetector, newLock);
return newLock; return newLock;
} }
} }
@ -307,7 +323,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
} }
addTicket(serverLevel, chunkX, chunkZ); addTicket(serverLevel, chunkX, chunkZ);
return (LevelChunk) chunk.getHandle(ChunkStatus.FULL); return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -332,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) { if (chunkHolder == null) {
return; return;
@ -353,7 +369,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
if (levelChunk == null) { if (levelChunk == null) {
return; return;
} }
TaskManager.taskManager().task(() -> { StampLockHolder lockHolder = new StampLockHolder();
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
if (lockHolder.chunkLock == null) {
return;
}
MinecraftServer.getServer().execute(() -> {
try {
ClientboundLevelChunkWithLightPacket packet; ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket( packet = new ClientboundLevelChunkWithLightPacket(
@ -361,7 +383,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
null, null,
null, null,
true,
false // last false is to not bother with x-ray false // last false is to not bother with x-ray
); );
} else { } else {
@ -370,11 +391,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
levelChunk, levelChunk,
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
null, null,
null, null
true
); );
} }
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
} finally {
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
}
}); });
} }
@ -404,7 +427,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -477,12 +500,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
.getBukkitImplAdapter() .getBukkitImplAdapter()
.getInternalBiomeId( .getInternalBiomeId(
BiomeTypes.PLAINS)), BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES
null
); );
} }
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); return new LevelChunkSection(blockStatePalettedContainer, biomes);
} catch (final Throwable e) { } catch (final Throwable e) {
throw e; throw e;
} finally { } finally {
@ -495,20 +517,26 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (biomes == null) { if (biomes == null) {
return new LevelChunkSection(layer, biomeRegistry); return new LevelChunkSection(biomeRegistry);
} }
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>( PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY, Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(), Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES, PalettedContainer.Strategy.SECTION_STATES
null
); );
return new LevelChunkSection(layer, dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
}
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
} }
/** /**
@ -545,8 +573,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry, biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES
null
); );
final Palette<Holder<Biome>> biomePalette; final Palette<Holder<Biome>> biomePalette;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;

Datei anzeigen

@ -0,0 +1,77 @@
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.math.IntPair;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
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.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLevel, ChunkPos> {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT);
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<?> queue) {
super(serverLevel, queue);
}
@Override
protected ChunkPos createChunkPos(final long chunkKey) {
return new ChunkPos(chunkKey);
}
@Override
protected long asLong(final int chunkX, final int chunkZ) {
return ChunkPos.asLong(chunkX, chunkZ);
}
@Override
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
chunkPos,
LIGHT_LEVEL,
Unit.INSTANCE
));
}
protected void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
protected void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
}

Datei anzeigen

@ -1,23 +1,20 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; 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.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class PaperweightStarlightRelighterFactory implements RelighterFactory { public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override @Override
public @Nonnull public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<?> queue) {
@SuppressWarnings("rawtypes")
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName()); org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) { if (w == null) {
return NullRelighter.INSTANCE; return NullRelighter.INSTANCE;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag; import com.sk89q.jnbt.LazyCompoundTag;
@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.NumericTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, Tag> getValue() { public Map<String, Tag<?, ?>> getValue() {
if (compoundTag == null) { if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
} }
@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@Override @Override
public CompoundBinaryTag asBinaryTag() { public LinCompoundTag toLinTag() {
getValue(); getValue();
return compoundTag.asBinaryTag(); return compoundTag.toLinTag();
} }
public boolean containsKey(String key) { public boolean containsKey(String key) {
@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<Tag> getList(String key) { public List<? extends Tag<?, ?>> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) { if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag> list = new ArrayList<>(); ArrayList<Tag<?, ?>> list = new ArrayList<>();
for (net.minecraft.nbt.Tag elem : nbtList) { for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag)); list.add(new PaperweightLazyCompoundTag(compoundTag));
@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) { public <T extends Tag<?, ?>> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key); ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) { if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue(); return (List<T>) listTag.getValue();

Datei anzeigen

@ -0,0 +1,303 @@
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.queue.implementation.chunk.ChunkCache;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.ProgressListener;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.generator.BiomeProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Map;
import java.util.OptionalLong;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator {
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field generatorSettingBaseSupplierField;
static {
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
}
paperConfigField = tmpPaperConfigField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerLevel freshWorld;
private LevelStorageSource.LevelStorageAccess session;
private Path tempDir;
public PaperweightRegen(
World originalBukkitWorld,
Region region,
Extent target,
RegenOptions options
) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
while (shouldKeepTicking.getAsBoolean()) {
if (!this.freshWorld.getChunkSource().pollTask()) {
return;
}
}
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
seed = options.getSeed().orElse(originalServerWorld.getSeed());
return true;
}
@Override
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
new LevelStem(
originalServerWorld.dimensionTypeRegistration(),
originalServerWorld.getChunkSource().getGenerator()
),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalServerWorld.getRandomSequences(),
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
}
@Override
public void save(
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled
) {
// noop, spigot
}
@Override
public void save(
@Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled,
final boolean close
) {
// noop, paper
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
}
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshWorld.getChunkSource().getDataStorage().cache.clear();
freshWorld.getChunkSource().close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
}
@Override
public void onStatusChange(
final @NotNull ChunkPos pos,
@org.jetbrains.annotations.Nullable final ChunkStatus status
) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
}

Datei anzeigen

@ -1,26 +1,17 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration()
plugins { plugins {
java java
} }
applyPaperweightAdapterConfiguration()
repositories { repositories {
mavenCentral()
gradlePluginPortal() gradlePluginPortal()
} }
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
configurations.all {
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
dependencies { dependencies {
the<PaperweightUserDependenciesExtension>().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.6-R0.1-SNAPSHOT/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.6-R0.1-20241030.191541-126")
compileOnly(libs.paperlib) compileOnly(libs.paperlib)
} }

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -29,18 +29,19 @@ import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DSL.TypeReference; import com.mojang.datafixers.DSL.TypeReference;
import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic; import com.mojang.serialization.Dynamic;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.StringTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.GsonHelper; import net.minecraft.util.GsonHelper;
import net.minecraft.util.StringUtil; import net.minecraft.util.StringUtil;
import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.DataFixers;
@ -48,6 +49,7 @@ import net.minecraft.util.datafix.fixes.References;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -66,28 +68,27 @@ import java.util.stream.Collectors;
/** /**
* Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2)
* <p> *
* We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy
* which is safer, faster and cleaner code. * which is safer, faster and cleaner code.
* <p> *
* The pre DFU code did not fail when the Source version was unknown. * The pre DFU code did not fail when the Source version was unknown.
* <p> *
* This class also provides util methods for converting compounds to wrap the update call to * This class also provides util methods for converting compounds to wrap the update call to
* receive the source version in the compound * receive the source version in the compound
*/ */
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({ "rawtypes", "unchecked" })
class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { public class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer {
//FAWE start - BinaryTag
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T fixUp(FixType<T> type, T original, int srcVer) { public <T> T fixUp(FixType<T> type, T original, int srcVer) {
if (type == FixTypes.CHUNK) { if (type == FixTypes.CHUNK) {
return (T) fixChunk((CompoundBinaryTag) original, srcVer); return (T) fixChunk((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_ENTITY) { } else if (type == FixTypes.BLOCK_ENTITY) {
return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); return (T) fixBlockEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.ENTITY) { } else if (type == FixTypes.ENTITY) {
return (T) fixEntity((CompoundBinaryTag) original, srcVer); return (T) fixEntity((LinCompoundTag) original, srcVer);
} else if (type == FixTypes.BLOCK_STATE) { } else if (type == FixTypes.BLOCK_STATE) {
return (T) fixBlockState((String) original, srcVer); return (T) fixBlockState((String) original, srcVer);
} else if (type == FixTypes.ITEM_TYPE) { } else if (type == FixTypes.ITEM_TYPE) {
@ -98,34 +99,28 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return original; return original;
} }
private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt);
net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer);
return (CompoundBinaryTag) adapter.toNativeBinary(fixed); return (LinCompoundTag) adapter.toNativeLin(fixed);
} }
//FAWE end
private String fixBlockState(String blockState, int srcVer) { private String fixBlockState(String blockState, int srcVer) {
net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState);
Dynamic<net.minecraft.nbt.Tag> dynamic = new Dynamic<>(OPS_NBT, stateNBT); Dynamic<net.minecraft.nbt.Tag> dynamic = new Dynamic<>(OPS_NBT, stateNBT);
net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update( net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue();
References.BLOCK_STATE,
dynamic,
srcVer,
DATA_VERSION
).getValue();
return nbtToState(fixed); return nbtToState(fixed);
} }
@ -135,11 +130,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (tagCompound.contains("Properties", 10)) { if (tagCompound.contains("Properties", 10)) {
sb.append('['); sb.append('[');
net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties");
sb.append(props sb.append(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(",")));
.getAllKeys()
.stream()
.map(k -> k + "=" + props.getString(k).replace("\"", ""))
.collect(Collectors.joining(",")));
sb.append(']'); sb.append(']');
} }
return sb.toString(); return sb.toString();
@ -182,7 +173,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private static final NbtOps OPS_NBT = NbtOps.INSTANCE; private static final NbtOps OPS_NBT = NbtOps.INSTANCE;
private static final int LEGACY_VERSION = 1343; private static final int LEGACY_VERSION = 1343;
private static int DATA_VERSION; private static int DATA_VERSION;
static PaperweightDataConverters INSTANCE; public static PaperweightDataConverters INSTANCE;
private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataConverter>> converters = new EnumMap<>(LegacyType.class);
private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class); private final Map<LegacyType, List<DataInspector>> inspectors = new EnumMap<>(LegacyType.class);
@ -213,7 +204,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
} }
} }
PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { public PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) {
super(dataVersion); super(dataVersion);
DATA_VERSION = dataVersion; DATA_VERSION = dataVersion;
INSTANCE = this; INSTANCE = this;
@ -225,13 +216,17 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
// Called after fixers are built and ready for FIXING // Called after fixers are built and ready for FIXING
@Override @Override
public DataFixer build(final Executor executor) { public DataFixer buildUnoptimized() {
return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer());
} }
@Override
public DataFixer buildOptimized(final Set<DSL.TypeReference> requiredTypes, Executor executor) {
return buildUnoptimized();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private class WrappedDataFixer implements DataFixer { private class WrappedDataFixer implements DataFixer {
private final DataFixer realFixer; private final DataFixer realFixer;
WrappedDataFixer(DataFixer realFixer) { WrappedDataFixer(DataFixer realFixer) {
@ -252,12 +247,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return realFixer.update(type, dynamic, sourceVer, targetVer); return realFixer.update(type, dynamic, sourceVer, targetVer);
} }
private net.minecraft.nbt.CompoundTag convert( private net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int desiredVersion) {
LegacyType type,
net.minecraft.nbt.CompoundTag cmp,
int sourceVer,
int desiredVersion
) {
List<DataConverter> converters = PaperweightDataConverters.this.converters.get(type); List<DataConverter> converters = PaperweightDataConverters.this.converters.get(type);
if (converters != null && !converters.isEmpty()) { if (converters != null && !converters.isEmpty()) {
for (DataConverter converter : converters) { for (DataConverter converter : converters) {
@ -282,7 +272,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
public Schema getSchema(int i) { public Schema getSchema(int i) {
return realFixer.getSchema(i); return realFixer.getSchema(i);
} }
} }
public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) {
@ -293,12 +282,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return convert(type.getDFUType(), cmp, sourceVer); return convert(type.getDFUType(), cmp, sourceVer);
} }
public static net.minecraft.nbt.CompoundTag convert( public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
LegacyType type,
net.minecraft.nbt.CompoundTag cmp,
int sourceVer,
int targetVer
) {
return convert(type.getDFUType(), cmp, sourceVer, targetVer); return convert(type.getDFUType(), cmp, sourceVer, targetVer);
} }
@ -311,25 +295,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return convert(type, cmp, sourceVer, DATA_VERSION); return convert(type, cmp, sourceVer, DATA_VERSION);
} }
public static net.minecraft.nbt.CompoundTag convert( public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
TypeReference type,
net.minecraft.nbt.CompoundTag cmp,
int sourceVer,
int targetVer
) {
if (sourceVer >= targetVer) { if (sourceVer >= targetVer) {
return cmp; return cmp;
} }
return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue();
.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer)
.getValue();
} }
public interface DataInspector { public interface DataInspector {
net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer); net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer);
} }
public interface DataConverter { public interface DataConverter {
@ -337,7 +312,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
int getDataVersion(); int getDataVersion();
net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp);
} }
@ -615,13 +589,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return key; return key;
} }
private static void convertCompound( private static void convertCompound(LegacyType type, net.minecraft.nbt.CompoundTag cmp, String key, int sourceVer, int targetVer) {
LegacyType type,
net.minecraft.nbt.CompoundTag cmp,
String key,
int sourceVer,
int targetVer
) {
cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer));
} }
@ -697,7 +665,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorBlockEntity implements DataInspector { private static class DataInspectorBlockEntity implements DataInspector {
@ -844,8 +811,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private static class DataInspectorEntity implements DataInspector { private static class DataInspectorEntity implements DataInspector {
private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class);
DataInspectorEntity() { DataInspectorEntity() {
} }
@ -880,7 +845,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
@ -900,12 +864,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
abstract net.minecraft.nbt.CompoundTag inspectChecked( abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer);
net.minecraft.nbt.CompoundTag nbttagcompound,
int sourceVer,
int targetVer
);
} }
private static class DataInspectorItemList extends DataInspectorTagged { private static class DataInspectorItemList extends DataInspectorTagged {
@ -924,7 +883,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return nbttagcompound; return nbttagcompound;
} }
} }
private static class DataInspectorItem extends DataInspectorTagged { private static class DataInspectorItem extends DataInspectorTagged {
@ -943,7 +901,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return nbttagcompound; return nbttagcompound;
} }
} }
private static class DataConverterMaterialId implements DataConverter { private static class DataConverterMaterialId implements DataConverter {
@ -1344,7 +1301,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterBanner implements DataConverter { private static class DataConverterBanner implements DataConverter {
@ -1391,7 +1347,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterPotionId implements DataConverter { private static class DataConverterPotionId implements DataConverter {
@ -1669,15 +1624,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private static class DataConverterMinecart implements DataConverter { private static class DataConverterMinecart implements DataConverter {
private static final List<String> a = Lists.newArrayList( private static final List<String> a = Lists.newArrayList("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock");
"MinecartRideable",
"MinecartChest",
"MinecartFurnace",
"MinecartTNT",
"MinecartSpawner",
"MinecartHopper",
"MinecartCommandBlock"
);
DataConverterMinecart() { DataConverterMinecart() {
} }
@ -1701,7 +1648,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterMobSpawner implements DataConverter { private static class DataConverterMobSpawner implements DataConverter {
@ -1746,7 +1692,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
} }
private static class DataConverterUUID implements DataConverter { private static class DataConverterUUID implements DataConverter {
@ -1765,47 +1710,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterHealth implements DataConverter { private static class DataConverterHealth implements DataConverter {
private static final Set<String> a = Sets.newHashSet( private static final Set<String> 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");
"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() { DataConverterHealth() {
} }
@ -1834,7 +1743,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterSaddle implements DataConverter { private static class DataConverterSaddle implements DataConverter {
@ -1859,7 +1767,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterHanging implements DataConverter { private static class DataConverterHanging implements DataConverter {
@ -1898,7 +1805,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterDropChances implements DataConverter { private static class DataConverterDropChances implements DataConverter {
@ -1922,15 +1828,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (cmp.contains("ArmorDropChances", 9)) { if (cmp.contains("ArmorDropChances", 9)) {
nbttaglist = cmp.getList("ArmorDropChances", 5); nbttaglist = cmp.getList("ArmorDropChances", 5);
if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat( if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat(2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) {
2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) {
cmp.remove("ArmorDropChances"); cmp.remove("ArmorDropChances");
} }
} }
return cmp; return cmp;
} }
} }
private static class DataConverterRiding implements DataConverter { private static class DataConverterRiding implements DataConverter {
@ -1966,7 +1870,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
nbttagcompound.remove("Riding"); nbttagcompound.remove("Riding");
return nbttagcompound1; return nbttagcompound1;
} }
} }
private static class DataConverterBook implements DataConverter { private static class DataConverterBook implements DataConverter {
@ -1991,12 +1894,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { 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)) { 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 { } else {
try { try {
object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true);
if (object == null) { if (object == null) {
object = new TextComponent(""); object = Component.literal("");
} }
} catch (JsonParseException jsonparseexception) { } catch (JsonParseException jsonparseexception) {
; ;
@ -2004,7 +1907,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (object == null) { if (object == null) {
try { try {
object = Component.Serializer.fromJson(s); object = Component.Serializer.fromJson(s, MinecraftServer.getServer().registryAccess());
} catch (JsonParseException jsonparseexception1) { } catch (JsonParseException jsonparseexception1) {
; ;
} }
@ -2012,21 +1915,21 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (object == null) { if (object == null) {
try { try {
object = Component.Serializer.fromJsonLenient(s); object = Component.Serializer.fromJsonLenient(s, MinecraftServer.getServer().registryAccess());
} catch (JsonParseException jsonparseexception2) { } catch (JsonParseException jsonparseexception2) {
; ;
} }
} }
if (object == null) { if (object == null) {
object = new TextComponent(s); object = Component.literal(s);
} }
} }
} else { } else {
object = new TextComponent(""); object = Component.literal("");
} }
nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess())));
} }
nbttagcompound1.put("pages", nbttaglist); nbttagcompound1.put("pages", nbttaglist);
@ -2035,7 +1938,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterCookedFish implements DataConverter { private static class DataConverterCookedFish implements DataConverter {
@ -2056,7 +1958,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterZombie implements DataConverter { private static class DataConverterZombie implements DataConverter {
@ -2099,7 +2000,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
private int convert(int i) { private int convert(int i) {
return i >= 0 && i < 6 ? i : -1; return i >= 0 && i < 6 ? i : -1;
} }
} }
private static class DataConverterVBO implements DataConverter { private static class DataConverterVBO implements DataConverter {
@ -2115,7 +2015,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
cmp.putString("useVbo", "true"); cmp.putString("useVbo", "true");
return cmp; return cmp;
} }
} }
private static class DataConverterGuardian implements DataConverter { private static class DataConverterGuardian implements DataConverter {
@ -2138,7 +2037,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterSkeleton implements DataConverter { private static class DataConverterSkeleton implements DataConverter {
@ -2167,7 +2065,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterZombieType implements DataConverter { private static class DataConverterZombieType implements DataConverter {
@ -2206,7 +2103,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterHorse implements DataConverter { private static class DataConverterHorse implements DataConverter {
@ -2249,7 +2145,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterTileEntity implements DataConverter { private static class DataConverterTileEntity implements DataConverter {
@ -2412,8 +2307,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) {
String s = cmp.getString("id"); String s = cmp.getString("id");
if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals( if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) {
s)) {
net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag");
if (!nbttagcompound1.contains("Potion", 8)) { if (!nbttagcompound1.contains("Potion", 8)) {
@ -2427,7 +2321,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterShulker implements DataConverter { private static class DataConverterShulker implements DataConverter {
@ -2446,12 +2339,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterShulkerBoxItem implements DataConverter { 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() { DataConverterShulkerBoxItem() {
} }
@ -2488,7 +2380,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterShulkerBoxBlock implements DataConverter { private static class DataConverterShulkerBoxBlock implements DataConverter {
@ -2507,7 +2398,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterLang implements DataConverter { private static class DataConverterLang implements DataConverter {
@ -2526,7 +2416,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterTotem implements DataConverter { private static class DataConverterTotem implements DataConverter {
@ -2545,7 +2434,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterBedBlock implements DataConverter { private static class DataConverterBedBlock implements DataConverter {
@ -2593,7 +2481,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterBedItem implements DataConverter { private static class DataConverterBedItem implements DataConverter {
@ -2612,16 +2499,14 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataConverterSignText implements DataConverter { private static class DataConverterSignText implements DataConverter {
public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() {
MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
JsonParseException {
if (jsonelement.isJsonPrimitive()) { if (jsonelement.isJsonPrimitive()) {
return new TextComponent(jsonelement.getAsString()); return Component.literal(jsonelement.getAsString());
} else if (jsonelement.isJsonArray()) { } else if (jsonelement.isJsonArray()) {
JsonArray jsonarray = jsonelement.getAsJsonArray(); JsonArray jsonarray = jsonelement.getAsJsonArray();
MutableComponent ichatbasecomponent = null; MutableComponent ichatbasecomponent = null;
@ -2629,11 +2514,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
while (iterator.hasNext()) { while (iterator.hasNext()) {
JsonElement jsonelement1 = (JsonElement) iterator.next(); JsonElement jsonelement1 = (JsonElement) iterator.next();
MutableComponent ichatbasecomponent1 = this.a( MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext);
jsonelement1,
jsonelement1.getClass(),
jsondeserializationcontext
);
if (ichatbasecomponent == null) { if (ichatbasecomponent == null) {
ichatbasecomponent = ichatbasecomponent1; ichatbasecomponent = ichatbasecomponent1;
@ -2648,11 +2529,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
} }
} }
public Object deserialize( public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
JsonElement jsonelement,
Type type,
JsonDeserializationContext jsondeserializationcontext
) throws JsonParseException {
return this.a(jsonelement, type, jsondeserializationcontext); return this.a(jsonelement, type, jsondeserializationcontext);
} }
}).create(); }).create();
@ -2681,12 +2558,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { 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)) { 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 { } else {
try { try {
object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true);
if (object == null) { if (object == null) {
object = new TextComponent(""); object = Component.literal("");
} }
} catch (JsonParseException jsonparseexception) { } catch (JsonParseException jsonparseexception) {
; ;
@ -2694,7 +2571,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (object == null) { if (object == null) {
try { try {
object = Component.Serializer.fromJson(s1); object = Component.Serializer.fromJson(s1, MinecraftServer.getServer().registryAccess());
} catch (JsonParseException jsonparseexception1) { } catch (JsonParseException jsonparseexception1) {
; ;
} }
@ -2702,27 +2579,25 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
if (object == null) { if (object == null) {
try { try {
object = Component.Serializer.fromJsonLenient(s1); object = Component.Serializer.fromJsonLenient(s1, MinecraftServer.getServer().registryAccess());
} catch (JsonParseException jsonparseexception2) { } catch (JsonParseException jsonparseexception2) {
; ;
} }
} }
if (object == null) { if (object == null) {
object = new TextComponent(s1); object = Component.literal(s1);
} }
} }
} else { } else {
object = new TextComponent(""); object = Component.literal("");
} }
nbttagcompound.putString(s, Component.Serializer.toJson(object)); nbttagcompound.putString(s, Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess()));
} }
} }
private static class DataInspectorPlayerVehicle implements DataInspector { private static class DataInspectorPlayerVehicle implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
if (cmp.contains("RootVehicle", 10)) { if (cmp.contains("RootVehicle", 10)) {
@ -2735,11 +2610,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorLevelPlayer implements DataInspector { private static class DataInspectorLevelPlayer implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
if (cmp.contains("Player", 10)) { if (cmp.contains("Player", 10)) {
@ -2748,11 +2621,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorStructure implements DataInspector { private static class DataInspectorStructure implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
net.minecraft.nbt.ListTag nbttaglist; net.minecraft.nbt.ListTag nbttaglist;
@ -2783,11 +2654,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorChunks implements DataInspector { private static class DataInspectorChunks implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
if (cmp.contains("Level", 10)) { if (cmp.contains("Level", 10)) {
@ -2799,15 +2668,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
nbttaglist = nbttagcompound1.getList("Entities", 10); nbttaglist = nbttagcompound1.getList("Entities", 10);
for (j = 0; j < nbttaglist.size(); ++j) { for (j = 0; j < nbttaglist.size(); ++j) {
nbttaglist.set( nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer));
j,
convert(
LegacyType.ENTITY,
(net.minecraft.nbt.CompoundTag) nbttaglist.get(j),
sourceVer,
targetVer
)
);
} }
} }
@ -2815,26 +2676,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
nbttaglist = nbttagcompound1.getList("TileEntities", 10); nbttaglist = nbttagcompound1.getList("TileEntities", 10);
for (j = 0; j < nbttaglist.size(); ++j) { for (j = 0; j < nbttaglist.size(); ++j) {
nbttaglist.set( nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer));
j,
convert(
LegacyType.BLOCK_ENTITY,
(net.minecraft.nbt.CompoundTag) nbttaglist.get(j),
sourceVer,
targetVer
)
);
} }
} }
} }
return cmp; return cmp;
} }
} }
private static class DataInspectorEntityPassengers implements DataInspector { private static class DataInspectorEntityPassengers implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
if (cmp.contains("Passengers", 9)) { if (cmp.contains("Passengers", 9)) {
@ -2847,11 +2698,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorPlayer implements DataInspector { private static class DataInspectorPlayer implements DataInspector {
@Override @Override
public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) {
convertItems(cmp, "Inventory", sourceVer, targetVer); convertItems(cmp, "Inventory", sourceVer, targetVer);
@ -2866,11 +2715,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorVillagers implements DataInspector { private static class DataInspectorVillagers implements DataInspector {
ResourceLocation entityVillager = getKey("EntityVillager"); ResourceLocation entityVillager = getKey("EntityVillager");
@Override @Override
@ -2894,11 +2741,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorMobSpawnerMinecart implements DataInspector { private static class DataInspectorMobSpawnerMinecart implements DataInspector {
ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner");
ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner");
@ -2913,11 +2758,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorMobSpawnerMobs implements DataInspector { private static class DataInspectorMobSpawnerMobs implements DataInspector {
ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner");
@Override @Override
@ -2938,11 +2781,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
private static class DataInspectorCommandBlock implements DataInspector { private static class DataInspectorCommandBlock implements DataInspector {
ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); ResourceLocation tileEntityCommand = getKey("TileEntityCommand");
@Override @Override
@ -2955,7 +2796,5 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
return cmp; return cmp;
} }
} }
} }

Datei anzeigen

@ -17,18 +17,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component; 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.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat; import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity; 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.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
@ -37,15 +38,14 @@ import java.util.OptionalInt;
import java.util.UUID; import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer { 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 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) { PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO);
} }
@Override @Override
@ -72,17 +72,13 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void updateOptions(ServerboundClientInformationPacket packet) { public void updateOptions(ClientInformation clientOptions) {
} }
@Override @Override
public void displayClientMessage(Component message, boolean actionBar) { public void displayClientMessage(Component message, boolean actionBar) {
} }
@Override
public void sendMessage(Component message, ChatType type, UUID sender) {
}
@Override @Override
public void awardStat(Stat<?> stat, int amount) { public void awardStat(Stat<?> stat, int amount) {
} }
@ -97,7 +93,6 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void openTextEdit(SignBlockEntity sign) { public void openTextEdit(SignBlockEntity sign, boolean front) {
} }
} }

Datei anzeigen

@ -17,31 +17,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements
WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
private static final int NOTIFY = 2; private static final int NOTIFY = 2;
@ -83,19 +83,12 @@ public class PaperweightWorldNativeAccess implements
@Nullable @Nullable
@Override @Override
public net.minecraft.world.level.block.state.BlockState setBlockState( public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) {
LevelChunk chunk,
BlockPos position,
net.minecraft.world.level.block.state.BlockState state
) {
return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
} }
@Override @Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) {
net.minecraft.world.level.block.state.BlockState block,
BlockPos position
) {
return Block.updateFromNeighbourShapes(block, getWorld(), position); return Block.updateFromNeighbourShapes(block, getWorld(), position);
} }
@ -110,17 +103,19 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false; return false;
} }
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override @Override
public void notifyBlockUpdate( public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
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) { if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
} }
@ -128,7 +123,7 @@ public class PaperweightWorldNativeAccess implements
@Override @Override
public boolean isChunkTicking(LevelChunk chunk) { public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -139,11 +134,7 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public void notifyNeighbors( public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
ServerLevel world = getWorld(); ServerLevel world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.updateNeighborsAt(pos, oldState.getBlock()); world.updateNeighborsAt(pos, oldState.getBlock());
@ -162,27 +153,23 @@ public class PaperweightWorldNativeAccess implements
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false);
} }
@Override @Override
public void updateNeighbors( public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState,
int recursionLimit
) {
ServerLevel world = getWorld(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent( BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()),
CraftBlockData.fromData(newState)
);
world.getCraftServer().getPluginManager().callEvent(event); world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
@ -193,19 +180,12 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
getWorld().onBlockStateChange(pos, oldState, newState); getWorld().onBlockStateChange(pos, oldState, newState);
} }
//FAWE start
@Override @Override
public void flush() { public void flush() {
} }
//FAWE end
} }

Datei anzeigen

@ -1,32 +1,27 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; 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.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 net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import javax.annotation.Nullable;
public class PaperweightBlockMaterial implements BlockMaterial { public class PaperweightBlockMaterial implements BlockMaterial {
private final Block block; private final Block block;
private final BlockState blockState; private final BlockState blockState;
private final Material material;
private final boolean isTranslucent;
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
private final int opacity; private final int opacity;
private final CompoundTag tile; private final FaweCompoundTag tile;
public PaperweightBlockMaterial(Block block) { public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState()); this(block, block.defaultBlockState());
@ -35,14 +30,8 @@ public class PaperweightBlockMaterial implements BlockMaterial {
public PaperweightBlockMaterial(Block block, BlockState blockState) { public PaperweightBlockMaterial(Block block, BlockState blockState) {
this.block = block; this.block = block;
this.blockState = blockState; this.blockState = blockState;
this.material = blockState.getMaterial();
this.craftBlockData = CraftBlockData.fromData(blockState); this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial(); this.craftMaterial = craftBlockData.getMaterial();
BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName(
"properties", "aO"));
this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo,
Refraction.pickName("canOcclude", "n")
);
opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
BlockPos.ZERO, BlockPos.ZERO,
@ -50,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
); );
tile = tileEntity == null tile = tileEntity == null
? null ? null
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
} }
public Block getBlock() { public Block getBlock() {
@ -65,10 +54,6 @@ public class PaperweightBlockMaterial implements BlockMaterial {
return craftBlockData; return craftBlockData;
} }
public Material getMaterial() {
return material;
}
@Override @Override
public boolean isAir() { public boolean isAir() {
return blockState.isAir(); return blockState.isAir();
@ -81,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isOpaque() { public boolean isOpaque() {
return material.isSolidBlocking(); return blockState.canOcclude();
} }
@Override @Override
@ -91,12 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isLiquid() { public boolean isLiquid() {
return material.isLiquid(); return !blockState.getFluidState().is(Fluids.EMPTY);
} }
@Override @Override
public boolean isSolid() { public boolean isSolid() {
return material.isSolid(); // No access to world -> EmptyBlockGetter
return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
} }
@Override @Override
@ -126,27 +112,28 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isFragileWhenPushed() { public boolean isFragileWhenPushed() {
return material.getPushReaction() == PushReaction.DESTROY; return blockState.getPistonPushReaction() == PushReaction.DESTROY;
} }
@Override @Override
public boolean isUnpushable() { public boolean isUnpushable() {
return material.getPushReaction() == PushReaction.BLOCK; return blockState.getPistonPushReaction() == PushReaction.BLOCK;
} }
@Override @Override
public boolean isTicksRandomly() { public boolean isTicksRandomly() {
return block.isRandomlyTicking(blockState); return blockState.isRandomlyTicking();
} }
@SuppressWarnings("deprecation")
@Override @Override
public boolean isMovementBlocker() { public boolean isMovementBlocker() {
return material.isSolid(); return blockState.blocksMotion();
} }
@Override @Override
public boolean isBurnable() { public boolean isBurnable() {
return material.isFlammable(); return craftMaterial.isBurnable();
} }
@Override @Override
@ -157,12 +144,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isReplacedDuringPlacement() { public boolean isReplacedDuringPlacement() {
return material.isReplaceable(); return blockState.canBeReplaced();
} }
@Override @Override
public boolean isTranslucent() { public boolean isTranslucent() {
return isTranslucent; return !blockState.canOcclude();
} }
@Override @Override
@ -176,14 +163,14 @@ public class PaperweightBlockMaterial implements BlockMaterial {
} }
@Override @Override
public CompoundTag getDefaultTile() { public @Nullable FaweCompoundTag defaultTile() {
return tile; return tile;
} }
@Override @Override
public int getMapColor() { public int getMapColor() {
// rgb field // rgb field
return material.getColor().col; return block.defaultMapColor().col;
} }
} }

Datei anzeigen

@ -1,29 +1,25 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Codec;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.bukkit.BukkitAdapter; 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.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.regen.PaperweightRegen;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -39,18 +35,14 @@ import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType; 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.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
@ -58,46 +50,51 @@ import com.sk89q.worldedit.world.registry.BlockMaterial;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry; import net.minecraft.core.WritableRegistry;
import net.minecraft.nbt.IntTag; import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; 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.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -107,27 +104,38 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements import static net.minecraft.core.registries.Registries.BIOME;
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.Tag, ServerLevel> {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
private static final Codec<DataComponentPatch> COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf(
"components", DataComponentPatch.EMPTY
).codec();
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 PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new PaperweightAdapter(); super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter());
}
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
return blockEntity -> FaweCompoundTag.of(
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
);
} }
@Nullable @Nullable
@ -231,7 +239,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
public Block getBlock(BlockType blockType) { 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 @Deprecated
@ -239,11 +248,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -259,12 +267,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseBlock getFullBlock(final Location location) { public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -278,8 +285,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// Read the NBT data // Read the NBT data
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess());
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
} }
@ -291,60 +298,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return SideEffectSet.defaults().getSideEffectsToApply(); return SideEffectSet.defaults().getSideEffectsToApply();
} }
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk;
LevelChunk levelChunk = craftChunk.getHandle();
Level level = levelChunk.getLevel();
BlockPos blockPos = new BlockPos(x, y, z);
net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState();
LevelChunkSection[] levelChunkSections = levelChunk.getSections();
int y4 = y >> 4;
LevelChunkSection section = levelChunkSections[y4];
net.minecraft.world.level.block.state.BlockState existing;
if (section == null) {
existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
} else {
existing = section.getBlockState(x & 15, y & 15, z & 15);
}
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
if (compoundTag != null || existing instanceof TileEntityBlock) {
level.setBlock(blockPos, blockState, 0);
// remove tile
if (compoundTag != null) {
// We will assume that the tile entity was created for us,
// though we do not do this on the Forge version
BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z));
blockEntity.load(tag); // readTagIntoTileEntity - load data
}
}
} else {
if (existing == blockState) {
return true;
}
levelChunk.setBlockState(blockPos, blockState, false);
}
if (update) {
level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0);
}
return true;
}
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess( return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world)));
this,
new WeakReference<>(((CraftWorld) world).getHandle())
);
} }
@Override @Override
@ -358,14 +314,14 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { Supplier<LinCompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, LinTag<?>> tags = NbtUtils.getLinCompoundTagValues(tag);
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", LinStringTag.of(id));
return CompoundBinaryTag.from(tags); return LinCompoundTag.of(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -489,9 +445,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { 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()); 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; // PlayerChunk.d players = map.players;
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
*/ Stream.empty(); */ Stream.empty();
@ -526,88 +483,64 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess( return blockState1.hasPostProcess(
((CraftWorld) world).getHandle(), getServerLevel(world),
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z())
); );
} }
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount() baseItemStack.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()))); final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData());
if (nbt != null) {
final DataComponentPatch patch = COMPONENTS_CODEC
.parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt)
.getOrThrow();
stack.applyComponents(patch);
}
return CraftItemStack.asCraftMirror(stack); return CraftItemStack.asCraftMirror(stack);
} }
@Override @Override
public boolean generateTree( protected void preCaptureStates(final ServerLevel serverLevel) {
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<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
} }
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally { @Override
protected List<org.bukkit.block.BlockState> getCapturedBlockStatesCopy(final ServerLevel serverLevel) {
return new ArrayList<>(serverLevel.capturedBlockStates.values());
}
@Override
protected void postCaptureBlockStates(final ServerLevel serverLevel) {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear(); 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;
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { protected ServerLevel getServerLevel(final World world) {
// Quickly add each entity to a list copy. return ((CraftWorld) world).getHandle();
List<Entity> mcEntities = new ArrayList<>();
((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add);
List<org.bukkit.entity.Entity> list = new ArrayList<>();
mcEntities.forEach((mcEnt) -> {
org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity();
if (bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
});
return list;
} }
@Override @Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart(
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); registryAccess.createSerializationContext(NbtOps.INSTANCE),
return weStack; nmsStack.getComponentsPatch()
).getOrThrow();
return new BaseItemStack(
BukkitAdapter.asItemType(itemStack.getType()),
LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)),
itemStack.getAmount()
);
} }
@Override @Override
@ -615,17 +548,12 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return parent.toNative(foreign); return parent.toNative(foreign);
} }
@Override
public BinaryTag toNativeBinary(final net.minecraft.nbt.Tag foreign) {
return parent.toNativeBinary(foreign);
}
@Override @Override
public net.minecraft.nbt.Tag fromNative(Tag foreign) { public net.minecraft.nbt.Tag fromNative(Tag foreign) {
if (foreign instanceof PaperweightLazyCompoundTag) { if (foreign instanceof PaperweightLazyCompoundTag) {
return ((PaperweightLazyCompoundTag) foreign).get(); return ((PaperweightLazyCompoundTag) foreign).get();
} }
return (net.minecraft.nbt.Tag) parent.fromNative(foreign); return parent.fromNative(foreign);
} }
@Override @Override
@ -643,8 +571,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
final Registry<Biome> registry = MinecraftServer final Registry<Biome> registry = MinecraftServer
.getServer() .getServer()
.registryAccess() .registryAccess()
.ownedRegistryOrThrow(Registry.BIOME_REGISTRY); .registryOrThrow(BIOME);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id());
Biome biome = registry.get(resourceLocation); Biome biome = registry.get(resourceLocation);
return registry.getId(biome); return registry.getId(biome);
} }
@ -654,8 +582,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer()) WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer())
.getServer() .getServer()
.registryAccess() .registryAccess()
.ownedRegistryOrThrow( .registryOrThrow(BIOME);
Registry.BIOME_REGISTRY);
List<ResourceLocation> keys = biomeRegistry.stream() List<ResourceLocation> keys = biomeRegistry.stream()
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); .map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
List<NamespacedKey> namespacedKeys = new ArrayList<>(); List<NamespacedKey> namespacedKeys = new ArrayList<>();
@ -697,4 +624,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return new PaperweightPostProcessor(); 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;
}
} }

Datei anzeigen

@ -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_R4;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.math.IntPair;
@ -9,21 +9,22 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -102,7 +103,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ));
boolean nextTick = lastTick.get() > currentTick; boolean nextTick = lastTick.get() > currentTick;
if (nextTick || cachedChanges.size() >= 1024) { if (nextTick || cachedChanges.size() >= 1024) {
if (nextTick) { if (nextTick) {
@ -132,15 +133,15 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
@Override @Override
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) {
// We will assume that the tile entity was created for us, // We will assume that the tile entity was created for us,
// though we do not do this on the other versions // though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) { if (blockEntity == null) {
return false; return false;
} }
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag);
blockEntity.load((CompoundTag) nativeTag); blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess());
return true; return true;
} }
@ -157,7 +158,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
@Override @Override
public boolean isChunkTicking(LevelChunk levelChunk) { public boolean isChunkTicking(LevelChunk levelChunk) {
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -181,7 +182,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
// Un-nest neighbour updating // Un-nest neighbour updating
for (Direction direction : NEIGHBOUR_ORDER) { for (Direction direction : NEIGHBOUR_ORDER) {
BlockPos shifted = blockPos.relative(direction); BlockPos shifted = blockPos.relative(direction);
level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); level.getBlockState(shifted).handleNeighborChanged(level, shifted, oldState.getBlock(), blockPos, false);
} }
} }
if (newState.hasAnalogOutputSignal()) { if (newState.hasAnalogOutputSignal()) {
@ -217,6 +218,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,
@ -246,7 +253,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };
@ -262,7 +269,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -29,8 +26,14 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.*; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
@ -42,24 +45,50 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTagType;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.*; import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static net.minecraft.core.registries.Registries.BIOME; import static net.minecraft.core.registries.Registries.BIOME;
@ -68,29 +97,34 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
private static final Function<BlockEntity, CompoundTag> nmsTile2We = public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); .getInstance()
.getBukkitImplAdapter()).blockEntityToCompoundTag();
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
.getInstance() .getInstance()
.getBukkitImplAdapter()); .getBukkitImplAdapter());
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
private final ReentrantLock callLock = new ReentrantLock();
private final ServerLevel serverLevel; private final ServerLevel serverLevel;
private final int chunkX; private final int chunkX;
private final int chunkZ; private final int chunkZ;
private final IntPair chunkPos;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
private final int minSectionPosition; private final int minSectionPosition;
private final int maxSectionPosition; private final int maxSectionPosition;
private final Registry<Biome> biomeRegistry; private final Registry<Biome> biomeRegistry;
private final IdMap<Holder<Biome>> biomeHolderIdMap; private final IdMap<Holder<Biome>> biomeHolderIdMap;
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
private final Object sendLock = new Object();
private LevelChunkSection[] sections; private LevelChunkSection[] sections;
private LevelChunk levelChunk; private LevelChunk levelChunk;
private DataLayer[] blockLight; private DataLayer[] blockLight;
private DataLayer[] skyLight; private DataLayer[] skyLight;
private boolean createCopy = false; private boolean createCopy = false;
private PaperweightGetBlocks_Copy copy = null;
private boolean forceLoadSections = true; private boolean forceLoadSections = true;
private boolean lightUpdate = false; private boolean lightUpdate = false;
private int copyKey = 0;
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ); this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -109,6 +143,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.blockLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()];
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
this.chunkPos = new IntPair(chunkX, chunkZ);
} }
public int getChunkX() { public int getChunkX() {
@ -125,13 +160,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
}
this.createCopy = createCopy; this.createCopy = createCopy;
// Increment regardless of whether copy will be created or not to return null from getCopy()
return ++this.copyKey;
} }
@Override @Override
public IChunkGet getCopy() { public IChunkGet getCopy(final int key) {
return copy; return copies.remove(key);
}
@Override
public void lockCall() {
this.callLock.lock();
}
@Override
public void unlockCall() {
this.callLock.unlock();
} }
@Override @Override
@ -215,23 +265,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getTile(int x, int y, int z) { public FaweCompoundTag tile(final int x, final int y, final int z) {
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
chunkX << 4), y, (z & 15) + ( chunkX << 4), y, (z & 15) + (
chunkZ << 4))); chunkZ << 4)));
if (blockEntity == null) { if (blockEntity == null) {
return null; return null;
} }
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); return NMS_TO_TILE.apply(blockEntity);
} }
@Override @Override
public Map<BlockVector3, CompoundTag> getTiles() { public Map<BlockVector3, FaweCompoundTag> tiles() {
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities(); Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
if (nmsTiles.isEmpty()) { if (nmsTiles.isEmpty()) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
} }
@Override @Override
@ -294,14 +345,22 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
Entity entity = serverLevel.getEntity(uuid); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
Entity entity = null;
for (Entity e : entities) {
if (e.getUUID().equals(uuid)) {
entity = e;
break;
}
}
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
} }
for (CompoundTag tag : getEntities()) { for (FaweCompoundTag tag : entities()) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -309,14 +368,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
ensureLoaded(serverLevel, chunkX, chunkZ); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
if (entities.isEmpty()) { if (entities.isEmpty()) {
return Collections.emptySet(); return Collections.emptyList();
} }
int size = entities.size(); int size = entities.size();
return new AbstractSet<>() { return new AbstractCollection<>() {
@Override @Override
public int size() { public int size() {
return size; return size;
@ -329,10 +388,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public boolean contains(Object get) { public boolean contains(Object get) {
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof FaweCompoundTag getTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); UUID getUUID = NbtUtils.uuid(getTag);
for (Entity entity : entities) { for (Entity entity : entities) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
@ -344,12 +403,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Nonnull @Nonnull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<FaweCompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
input.save(tag); input.save(tag);
return (CompoundTag) adapter.toNative(tag); return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
}).collect(Collectors.toList()); })::iterator;
return result.iterator(); return result.iterator();
} }
}; };
@ -366,12 +425,19 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
}
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
if (createCopy) {
if (copies.containsKey(copyKey)) {
throw new IllegalStateException("Copy key already used.");
}
copies.put(copyKey, copy);
}
try { try {
ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
// Remove existing tiles. Create a copy so that we can remove blocks // Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
List<BlockEntity> beacons = null; List<BlockEntity> beacons = null;
@ -443,6 +509,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -460,7 +528,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (paletteBiomes != null) {
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
}
} }
} }
} }
@ -502,11 +577,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
@ -517,6 +588,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
null, null,
newSection, newSection,
@ -573,16 +646,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
this::loadPrivately, this::loadPrivately,
setArr, setArr,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
); );
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
existingSection, existingSection,
newSection, newSection,
@ -656,7 +730,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) { for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.getEntities().get(uuid); Entity entity = serverLevel.getEntities().get(uuid);
if (entity != null) { if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
@ -668,48 +742,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
}; };
} }
Set<CompoundTag> entities = set.getEntities(); Collection<FaweCompoundTag> entities = set.entities();
if (entities != null && !entities.isEmpty()) { if (entities != null && !entities.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[2]; syncTasks = new Runnable[2];
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); Iterator<FaweCompoundTag> iterator = entities.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final CompoundTag nativeTag = iterator.next(); final FaweCompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final LinCompoundTag linTag = nativeTag.linTag();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
if (idTag == null || posTag == null || rotTag == null) { if (idTag == null || posTag == null || rotTag == null) {
LOGGER.error("Unknown entity tag: {}", nativeTag); LOGGER.error("Unknown entity tag: {}", nativeTag);
continue; continue;
} }
final double x = posTag.getDouble(0); final double x = posTag.get(0).valueAsDouble();
final double y = posTag.getDouble(1); final double y = posTag.get(1).valueAsDouble();
final double z = posTag.getDouble(2); final double z = posTag.get(2).valueAsDouble();
final float yaw = rotTag.getFloat(0); final float yaw = rotTag.get(0).valueAsFloat();
final float pitch = rotTag.getFloat(1); final float pitch = rotTag.get(1).valueAsFloat();
final String id = idTag.getValue(); final String id = idTag.value();
EntityType<?> type = EntityType.byString(id).orElse(null); EntityType<?> type = EntityType.byString(id).orElse(null);
if (type != null) { if (type != null) {
Entity entity = type.create(nmsWorld); Entity entity = type.create(serverLevel);
if (entity != null) { if (entity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag);
nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); entity.setUUID(NbtUtils.uuid(nativeTag));
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn( LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`", "Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id, id,
nmsWorld.getWorld().getName(), serverLevel.getWorld().getName(),
x, x,
y, y,
z z
@ -724,34 +797,33 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
// set tiles // set tiles
Map<BlockVector3, CompoundTag> tiles = set.getTiles(); Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
if (tiles != null && !tiles.isEmpty()) { if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[1]; syncTasks = new Runnable[1];
} }
syncTasks[0] = () -> { syncTasks[0] = () -> {
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) { for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue(); final FaweCompoundTag nativeTag = entry.getValue();
final BlockVector3 blockHash = entry.getKey(); final BlockVector3 blockHash = entry.getKey();
final int x = blockHash.getX() + bx; final int x = blockHash.x() + bx;
final int y = blockHash.getY(); final int y = blockHash.y();
final int z = blockHash.getZ() + bz; final int z = blockHash.z() + bz;
final BlockPos pos = new BlockPos(x, y, z); final BlockPos pos = new BlockPos(x, y, z);
synchronized (nmsWorld) { synchronized (serverLevel) {
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
if (tileEntity == null || tileEntity.isRemoved()) { if (tileEntity == null || tileEntity.isRemoved()) {
nmsWorld.removeBlockEntity(pos); serverLevel.removeBlockEntity(pos);
tileEntity = nmsWorld.getBlockEntity(pos); tileEntity = serverLevel.getBlockEntity(pos);
} }
if (tileEntity != null) { if (tileEntity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
nativeTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
tileEntity.load(tag); tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess());
} }
} }
} }
@ -763,15 +835,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
callback = null; callback = null;
} else { } else {
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
boolean finalLightUpdate = lightUpdate;
callback = () -> { callback = () -> {
// Set Modified // Set Modified
nmsChunk.setLightCorrect(true); // Set Modified nmsChunk.setLightCorrect(true); // Set Modified
nmsChunk.mustNotSave = false; nmsChunk.mustNotSave = false;
nmsChunk.setUnsaved(true); nmsChunk.setUnsaved(true);
// send to player // send to player
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
this.send(finalMask, finalLightUpdate); this.send();
} }
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); finalizer.run();
@ -793,7 +864,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -859,9 +930,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (super.sections[layer] != null) { if (super.sections[layer] != null) {
synchronized (super.sectionLocks[layer]) { synchronized (super.sectionLocks[layer]) {
if (super.sections[layer].isFull() && super.blocks[layer] != null) { if (super.sections[layer].isFull() && super.blocks[layer] != null) {
char[] blocks = new char[4096]; return super.blocks[layer];
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
return blocks;
} }
} }
} }
@ -869,8 +938,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send() {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
}
} }
/** /**
@ -981,9 +1052,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
public LevelChunkSection[] getSections(boolean force) { public LevelChunkSection[] getSections(boolean force) {
force &= forceLoadSections; force &= forceLoadSections;
sectionLock.readLock().lock();
LevelChunkSection[] tmp = sections; LevelChunkSection[] tmp = sections;
sectionLock.readLock().unlock();
if (tmp == null || force) { if (tmp == null || force) {
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
@ -1052,41 +1121,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> 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; BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return biomeData; return null;
} }
PalettedContainer<Holder<Biome>> biomeData = data.recreate();
for (int y = 0, index = 0; y < 4; y++) { for (int y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = sectionBiomes[index]; BiomeType biomeType = sectionBiomes[index];
if (biomeType == null) { if (biomeType == null) {
continue; biomeData.set(x, y, z, data.get(x, y, z));
} } else {
biomeData.set( biomeData.set(
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }
} }
}
return biomeData; return biomeData;
} }

Datei anzeigen

@ -1,29 +1,36 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.util.NbtUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.nbt.Tag;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -33,14 +40,16 @@ import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet { public class PaperweightGetBlocks_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Set<CompoundTag> entities = new HashSet<>();
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
private final Set<FaweCompoundTag> entities = new HashSet<>();
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; final ServerLevel serverLevel;
final LevelChunk levelChunk; final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null; private Holder<Biome>[][] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk; this.levelChunk = levelChunk;
@ -51,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
protected void storeTile(BlockEntity blockEntity) { protected void storeTile(BlockEntity blockEntity) {
@SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
tiles.put( tiles.put(
BlockVector3.at( BlockVector3.at(
blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ() blockEntity.getBlockPos().getZ()
), ),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId(DedicatedServer
.getServer()
.registryAccess())))
); );
} }
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); @SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag)); entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
return this.entities; return this.entities;
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
for (CompoundTag tag : entities) { for (FaweCompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -101,7 +103,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -138,7 +141,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
return PaperweightPlatformAdapter.adapt(biome, serverLevel); return PaperweightPlatformAdapter.adapt(biome, serverLevel);
} }
@ -165,17 +168,40 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
blocks[layer] = data; blocks[layer] = data;
} }
protected void storeBiomes(int layer, PalettedContainer<Holder<Biome>> biomeData) { protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) { if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()]; biomes = new Holder[getSectionCount()][];
}
if (biomes[layer] == null) {
biomes[layer] = new Holder[64];
}
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
if (PaperLib.isPaper()) {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
}
} else {
try {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} else {
LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}",
PalettedContainer.class.getSimpleName(),
biomeData.getClass().getSimpleName()
);
} }
biomes[layer] = biomeData;
} }
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)]; BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z); return state.toBaseBlock((IBlocks) this, x, y, z);
} }
@Override @Override
@ -187,6 +213,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public char[] load(int layer) { public char[] load(int layer) {
layer -= getMinSectionPosition(); layer -= getMinSectionPosition();
if (blocks[layer] == null) {
blocks[layer] = new char[4096];
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
}
return blocks[layer]; return blocks[layer];
} }
@ -201,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return BlockTypesCache.states[get(x, y, z)]; return BlockTypesCache.states[get(x, y, z)];
} }
@Override
public Map<BlockVector3, FaweCompoundTag> tiles() {
return tiles;
}
@Override
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@Override @Override
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
return 0; return 0;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
@ -10,10 +10,10 @@ public class PaperweightMapChunkUtil extends MapChunkUtil<ClientboundLevelChunkW
public PaperweightMapChunkUtil() throws NoSuchFieldException { public PaperweightMapChunkUtil() throws NoSuchFieldException {
fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a"));
fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "b"));
fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "c"));
fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b"));
fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "d"));
fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c"));
fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d"));
fieldX.setAccessible(true); fieldX.setAccessible(true);

Datei anzeigen

@ -0,0 +1,745 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
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.math.IntPair;
import com.fastasyncworldedit.core.util.MathMan;
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.MinecraftServer;
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.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.chunk.status.ChunkStatus;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftChunk;
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 fieldBiomes;
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 MethodHandle PALETTED_CONTAINER_GET;
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);
Field tmpFieldBiomes;
try {
// Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf
} catch (NoSuchFieldException ignored) {
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf
}
fieldBiomes = tmpFieldBiomes;
fieldBiomes.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",
"k"
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
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", "N"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
POST_CHUNK_REWRITE = chunkRewrite;
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
Refraction.pickName("get", "a"),
int.class
);
palettedContaienrGet.setAccessible(true);
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
} 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(
String worldName,
IntPair pair,
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
}
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> 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<net.minecraft.world.level.block.state.BlockState> 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<org.bukkit.Chunk> 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(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
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 = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
}
if (levelChunk == null) {
return;
}
StampLockHolder lockHolder = new StampLockHolder();
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
if (lockHolder.chunkLock == null) {
return;
}
MinecraftServer.getServer().execute(() -> {
try {
ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
false // 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));
} finally {
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
}
});
}
private static List<ServerPlayer> 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<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
}
public static LevelChunkSection newChunkSection(
final int layer,
final Function<Integer, char[]> get,
char[] set,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (set == null) {
return newChunkSection(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<net.minecraft.world.level.block.state.BlockState> 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<net.minecraft.world.level.block.state.BlockState> 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<Holder<Biome>> 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(
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (biomes == null) {
return new LevelChunkSection(biomeRegistry);
}
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES
);
return new LevelChunkSection(dataPaletteBlocks, biomes);
}
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/
public static PalettedContainer<Holder<Biome>> getBiomePalettedContainer(
BiomeType[] biomes,
IdMap<Holder<Biome>> 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<BiomeType, Holder<Biome>> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Holder<Biome> 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<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES
);
final Palette<Holder<Biome>> 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> 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> biome, LevelAccessor levelAccessor) {
final Registry<Biome> 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<Entity> getEntities(LevelChunk chunk) {
ExceptionCollector<RuntimeException> collector = new ExceptionCollector<>();
if (PaperLib.isPaper()) {
if (POST_CHUNK_REWRITE) {
try {
//noinspection unchecked
return (List<Entity>) 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<Entity>) (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<net.minecraft.world.level.block.state.BlockState> {
@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<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator();
}
}
record FakeIdMapBiome(int size) implements IdMap<Biome> {
@Override
public int getId(final Biome entry) {
return 0;
}
@Nullable
@Override
public Biome byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<Biome> iterator() {
return Collections.emptyIterator();
}
}
}

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;

Datei anzeigen

@ -0,0 +1,77 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLevel, ChunkPos> {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT);
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<?> queue) {
super(serverLevel, queue);
}
@Override
protected ChunkPos createChunkPos(final long chunkKey) {
return new ChunkPos(chunkKey);
}
@Override
protected long asLong(final int chunkX, final int chunkZ) {
return ChunkPos.asLong(chunkX, chunkZ);
}
@Override
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
chunkPos,
LIGHT_LEVEL,
Unit.INSTANCE
));
}
protected void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
protected void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
}

Datei anzeigen

@ -1,23 +1,20 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class PaperweightStarlightRelighterFactory implements RelighterFactory { public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override @Override
public @Nonnull public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<?> queue) {
@SuppressWarnings("rawtypes")
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName()); org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) { if (w == null) {
return NullRelighter.INSTANCE; return NullRelighter.INSTANCE;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag; import com.sk89q.jnbt.LazyCompoundTag;
@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.NumericTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, Tag> getValue() { public Map<String, Tag<?, ?>> getValue() {
if (compoundTag == null) { if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
} }
@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@Override @Override
public CompoundBinaryTag asBinaryTag() { public LinCompoundTag toLinTag() {
getValue(); getValue();
return compoundTag.asBinaryTag(); return compoundTag.toLinTag();
} }
public boolean containsKey(String key) { public boolean containsKey(String key) {
@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<Tag> getList(String key) { public List<? extends Tag<?, ?>> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) { if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag> list = new ArrayList<>(); ArrayList<Tag<?, ?>> list = new ArrayList<>();
for (net.minecraft.nbt.Tag elem : nbtList) { for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag)); list.add(new PaperweightLazyCompoundTag(compoundTag));
@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) { public <T extends Tag<?, ?>> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key); ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) { if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue(); return (List<T>) listTag.getValue();

Datei anzeigen

@ -0,0 +1,302 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.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.queue.implementation.chunk.ChunkCache;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.ProgressListener;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.generator.BiomeProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Map;
import java.util.OptionalLong;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator {
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field generatorSettingBaseSupplierField;
static {
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
}
paperConfigField = tmpPaperConfigField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerLevel freshWorld;
private LevelStorageSource.LevelStorageAccess session;
private Path tempDir;
public PaperweightRegen(
World originalBukkitWorld,
Region region,
Extent target,
RegenOptions options
) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
while (shouldKeepTicking.getAsBoolean()) {
if (!this.freshWorld.getChunkSource().pollTask()) {
return;
}
}
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
seed = options.getSeed().orElse(originalServerWorld.getSeed());
return true;
}
@Override
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
new LevelStem(
originalServerWorld.dimensionTypeRegistration(),
originalServerWorld.getChunkSource().getGenerator()
),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalServerWorld.getRandomSequences(),
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
}
@Override
public void save(
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled
) {
// noop, spigot
}
@Override
public void save(
@Nullable final ProgressListener progressListener,
final boolean flush,
final boolean savingDisabled,
final boolean close
) {
// noop, paper
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
}
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshWorld.getChunkSource().getDataStorage().cache.clear();
freshWorld.getChunkSource().close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
}
@Override
public void onStatusChange(
final @NotNull ChunkPos pos,
@org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status
) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
}

Datei anzeigen

@ -0,0 +1,17 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.21.1-R0.1-20241121.101634-127")
compileOnly(libs.paperlib)
}

Datei anzeigen

@ -17,35 +17,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component; 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.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat; import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource; 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.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.UUID; import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer { 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 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) { PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO);
} }
@Override @Override
@ -61,28 +59,19 @@ class PaperweightFakePlayer extends ServerPlayer {
public void die(DamageSource damagesource) { public void die(DamageSource damagesource) {
} }
@Override
public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) {
return this;
}
@Override @Override
public OptionalInt openMenu(MenuProvider factory) { public OptionalInt openMenu(MenuProvider factory) {
return OptionalInt.empty(); return OptionalInt.empty();
} }
@Override @Override
public void updateOptions(ServerboundClientInformationPacket packet) { public void updateOptions(ClientInformation clientOptions) {
} }
@Override @Override
public void displayClientMessage(Component message, boolean actionBar) { public void displayClientMessage(Component message, boolean actionBar) {
} }
@Override
public void sendMessage(Component message, ChatType type, UUID sender) {
}
@Override @Override
public void awardStat(Stat<?> stat, int amount) { public void awardStat(Stat<?> stat, int amount) {
} }
@ -97,7 +86,6 @@ class PaperweightFakePlayer extends ServerPlayer {
} }
@Override @Override
public void openTextEdit(SignBlockEntity sign) { public void openTextEdit(SignBlockEntity sign, boolean front) {
} }
} }

Datei anzeigen

@ -17,31 +17,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
public class PaperweightWorldNativeAccess implements public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
private static final int NOTIFY = 2; private static final int NOTIFY = 2;
@ -83,19 +83,12 @@ public class PaperweightWorldNativeAccess implements
@Nullable @Nullable
@Override @Override
public net.minecraft.world.level.block.state.BlockState setBlockState( public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) {
LevelChunk chunk, return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
BlockPos position,
net.minecraft.world.level.block.state.BlockState state
) {
return chunk.setType(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
} }
@Override @Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) {
net.minecraft.world.level.block.state.BlockState block,
BlockPos position
) {
return Block.updateFromNeighbourShapes(block, getWorld(), position); return Block.updateFromNeighbourShapes(block, getWorld(), position);
} }
@ -110,17 +103,19 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) {
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false; return false;
} }
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override @Override
public void notifyBlockUpdate( public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
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) { if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
} }
@ -128,7 +123,7 @@ public class PaperweightWorldNativeAccess implements
@Override @Override
public boolean isChunkTicking(LevelChunk chunk) { public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -139,11 +134,7 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public void notifyNeighbors( public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
ServerLevel world = getWorld(); ServerLevel world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.updateNeighborsAt(pos, oldState.getBlock()); world.updateNeighborsAt(pos, oldState.getBlock());
@ -162,27 +153,23 @@ public class PaperweightWorldNativeAccess implements
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false);
} }
@Override @Override
public void updateNeighbors( public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState,
int recursionLimit
) {
ServerLevel world = getWorld(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent( BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()),
CraftBlockData.fromData(newState)
);
world.getCraftServer().getPluginManager().callEvent(event); world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
@ -193,11 +180,7 @@ public class PaperweightWorldNativeAccess implements
} }
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
getWorld().onBlockStateChange(pos, oldState, newState); getWorld().onBlockStateChange(pos, oldState, newState);
} }
@ -205,5 +188,4 @@ public class PaperweightWorldNativeAccess implements
public void flush() { public void flush() {
} }
} }

Datei anzeigen

@ -0,0 +1,90 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
/**
* Dedicated class to map all names that we use.
*
* <p>
* Overloads are split into multiple fields, as they <em>CAN</em> have different obfuscated names.
* </p>
*/
public final class StaticRefraction {
public static final String GET_CHUNK_FUTURE_MAIN_THREAD = Refraction.pickName(
"getChunkFutureMainThread", "c"
);
public static final String MAIN_THREAD_PROCESSOR = Refraction.pickName(
"mainThreadProcessor", "g"
);
public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e");
public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_");
/**
* {@code addFreshEntityWithPassengers(Entity entity)}.
*/
public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY = Refraction.pickName(
"addFreshEntityWithPassengers", "a_"
);
/**
* {@code addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason)}.
*/
public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY_SPAWN_REASON =
Refraction.pickName("addFreshEntityWithPassengers", "a_");
/**
* {@code addFreshEntity(Entity entity)}.
*/
public static final String ADD_FRESH_ENTITY = Refraction.pickName("addFreshEntity", "b");
/**
* {@code addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason)}.
*/
public static final String ADD_FRESH_ENTITY_SPAWN_REASON = Refraction.pickName(
"addFreshEntity", "b"
);
/**
* {@code getBlockEntity(BlockPos blockPos)}.
*/
public static final String GET_BLOCK_ENTITY = Refraction.pickName("getBlockEntity", "c_");
/**
* {@code setBlock(BlockPos blockPos, BlockState blockState, int flags)}.
*/
public static final String SET_BLOCK = Refraction.pickName("setBlock", "a");
/**
* {@code setBlock(BlockPos blockPos, BlockState blockState, int flags, int maxUpdateDepth)}.
*/
public static final String SET_BLOCK_MAX_UPDATE = Refraction.pickName("setBlock", "a");
public static final String REMOVE_BLOCK = Refraction.pickName("removeBlock", "a");
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop)}.
*/
public static final String DESTROY_BLOCK = Refraction.pickName("destroyBlock", "b");
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity)}.
*/
public static final String DESTROY_BLOCK_BREAKING_ENTITY = Refraction.pickName(
"destroyBlock", "a"
);
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity, int maxUpdateDepth)}.
*/
public static final String DESTROY_BLOCK_BREAKING_ENTITY_MAX_UPDATE = Refraction.pickName(
"destroyBlock", "a"
);
}

Datei anzeigen

@ -1,32 +1,27 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
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.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; 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.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 net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import javax.annotation.Nullable;
public class PaperweightBlockMaterial implements BlockMaterial { public class PaperweightBlockMaterial implements BlockMaterial {
private final Block block; private final Block block;
private final BlockState blockState; private final BlockState blockState;
private final Material material;
private final boolean isTranslucent;
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
private final int opacity; private final int opacity;
private final CompoundTag tile; private final FaweCompoundTag tile;
public PaperweightBlockMaterial(Block block) { public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState()); this(block, block.defaultBlockState());
@ -35,14 +30,8 @@ public class PaperweightBlockMaterial implements BlockMaterial {
public PaperweightBlockMaterial(Block block, BlockState blockState) { public PaperweightBlockMaterial(Block block, BlockState blockState) {
this.block = block; this.block = block;
this.blockState = blockState; this.blockState = blockState;
this.material = blockState.getMaterial();
this.craftBlockData = CraftBlockData.fromData(blockState); this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial(); 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); opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
BlockPos.ZERO, BlockPos.ZERO,
@ -50,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
); );
tile = tileEntity == null tile = tileEntity == null
? null ? null
: new PaperweightLazyCompoundTag(Suppliers.memoize(() -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); : PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
} }
public Block getBlock() { public Block getBlock() {
@ -65,10 +54,6 @@ public class PaperweightBlockMaterial implements BlockMaterial {
return craftBlockData; return craftBlockData;
} }
public Material getMaterial() {
return material;
}
@Override @Override
public boolean isAir() { public boolean isAir() {
return blockState.isAir(); return blockState.isAir();
@ -81,7 +66,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isOpaque() { public boolean isOpaque() {
return material.isSolidBlocking(); return blockState.canOcclude();
} }
@Override @Override
@ -91,12 +76,13 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isLiquid() { public boolean isLiquid() {
return material.isLiquid(); return !blockState.getFluidState().is(Fluids.EMPTY);
} }
@Override @Override
public boolean isSolid() { public boolean isSolid() {
return material.isSolid(); // No access to world -> EmptyBlockGetter
return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
} }
@Override @Override
@ -126,27 +112,28 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isFragileWhenPushed() { public boolean isFragileWhenPushed() {
return material.getPushReaction() == PushReaction.DESTROY; return blockState.getPistonPushReaction() == PushReaction.DESTROY;
} }
@Override @Override
public boolean isUnpushable() { public boolean isUnpushable() {
return material.getPushReaction() == PushReaction.BLOCK; return blockState.getPistonPushReaction() == PushReaction.BLOCK;
} }
@Override @Override
public boolean isTicksRandomly() { public boolean isTicksRandomly() {
return block.isRandomlyTicking(blockState); return blockState.isRandomlyTicking();
} }
@SuppressWarnings("deprecation")
@Override @Override
public boolean isMovementBlocker() { public boolean isMovementBlocker() {
return material.isSolid(); return blockState.blocksMotion();
} }
@Override @Override
public boolean isBurnable() { public boolean isBurnable() {
return material.isFlammable(); return craftMaterial.isBurnable();
} }
@Override @Override
@ -157,12 +144,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
@Override @Override
public boolean isReplacedDuringPlacement() { public boolean isReplacedDuringPlacement() {
return material.isReplaceable(); return blockState.canBeReplaced();
} }
@Override @Override
public boolean isTranslucent() { public boolean isTranslucent() {
return isTranslucent; return !blockState.canOcclude();
} }
@Override @Override
@ -176,14 +163,14 @@ public class PaperweightBlockMaterial implements BlockMaterial {
} }
@Override @Override
public CompoundTag getDefaultTile() { public @Nullable FaweCompoundTag defaultTile() {
return tile; return tile;
} }
@Override @Override
public int getMapColor() { public int getMapColor() {
// rgb field // rgb field
return material.getColor().col; return block.defaultMapColor().col;
} }
} }

Datei anzeigen

@ -1,29 +1,25 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Codec;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.bukkit.BukkitAdapter; 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.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen.PaperweightRegen;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -39,64 +35,66 @@ import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType; 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.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry; import net.minecraft.core.WritableRegistry;
import net.minecraft.nbt.IntTag; import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; 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.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -106,27 +104,38 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements import static net.minecraft.core.registries.Registries.BIOME;
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.Tag, ServerLevel> {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
private static final Codec<DataComponentPatch> COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf(
"components", DataComponentPatch.EMPTY
).codec();
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 PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil(); private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new PaperweightAdapter(); super(new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter());
}
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
return blockEntity -> FaweCompoundTag.of(
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
);
} }
@Nullable @Nullable
@ -144,7 +153,6 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return parent; return parent;
} }
@SuppressWarnings("unchecked")
private synchronized boolean init() { private synchronized boolean init() {
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false; return false;
@ -231,7 +239,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
public Block getBlock(BlockType blockType) { public Block getBlock(BlockType blockType) {
return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource())); return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK)
.get(ResourceLocation.fromNamespaceAndPath(blockType.getNamespace(), blockType.getResource()));
} }
@Deprecated @Deprecated
@ -239,11 +248,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -259,12 +267,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseBlock getFullBlock(final Location location) { public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location); Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX(); int x = location.getBlockX();
int y = location.getBlockY(); int y = location.getBlockY();
int z = location.getBlockZ(); int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
@ -278,8 +285,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// Read the NBT data // Read the NBT data
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess());
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
} }
} }
@ -291,67 +298,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return SideEffectSet.defaults().getSideEffectsToApply(); 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 @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess( return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world)));
this,
new WeakReference<>(((CraftWorld) world).getHandle())
);
} }
@Override @Override
@ -365,14 +314,14 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { Supplier<LinCompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, LinTag<?>> tags = NbtUtils.getLinCompoundTagValues(tag);
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", LinStringTag.of(id));
return CompoundBinaryTag.from(tags); return LinCompoundTag.of(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -496,9 +445,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { 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()); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && map.wasAccessibleSinceLastSave()) { if (map != null && wasAccessibleSinceLastSave(map)) {
boolean flag = false; boolean flag = false;
// PlayerChunk.d players = map.players; // PlayerChunk.d players = map.players;
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
@ -508,7 +457,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer) stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
.forEach(entityPlayer -> { .forEach(entityPlayer -> {
synchronized (chunkPacket) { synchronized (chunkPacket) {
ClientboundLevelChunkPacket nmsPacket = (ClientboundLevelChunkPacket) chunkPacket.getNativePacket(); ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket();
if (nmsPacket == null) { if (nmsPacket == null) {
nmsPacket = mapUtil.create(this, chunkPacket); nmsPacket = mapUtil.create(this, chunkPacket);
chunkPacket.setNativePacket(nmsPacket); chunkPacket.setNativePacket(nmsPacket);
@ -534,88 +483,64 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess( return blockState1.hasPostProcess(
((CraftWorld) world).getHandle(), getServerLevel(world),
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()) new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z())
); );
} }
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount() baseItemStack.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt()))); final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData());
if (nbt != null) {
final DataComponentPatch patch = COMPONENTS_CODEC
.parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt)
.getOrThrow();
stack.applyComponents(patch);
}
return CraftItemStack.asCraftMirror(stack); return CraftItemStack.asCraftMirror(stack);
} }
@Override @Override
public boolean generateTree( protected void preCaptureStates(final ServerLevel serverLevel) {
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<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
} }
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally { @Override
protected List<org.bukkit.block.BlockState> getCapturedBlockStatesCopy(final ServerLevel serverLevel) {
return new ArrayList<>(serverLevel.capturedBlockStates.values());
}
@Override
protected void postCaptureBlockStates(final ServerLevel serverLevel) {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear(); 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;
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { protected ServerLevel getServerLevel(final World world) {
// Quickly add each entity to a list copy. return ((CraftWorld) world).getHandle();
List<Entity> mcEntities = new ArrayList<>();
((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add);
List<org.bukkit.entity.Entity> list = new ArrayList<>();
mcEntities.forEach((mcEnt) -> {
org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity();
if (bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
});
return list;
} }
@Override @Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart(
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); registryAccess.createSerializationContext(NbtOps.INSTANCE),
return weStack; nmsStack.getComponentsPatch()
).getOrThrow();
return new BaseItemStack(
BukkitAdapter.asItemType(itemStack.getType()),
LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)),
itemStack.getAmount()
);
} }
@Override @Override
@ -646,19 +571,18 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
final Registry<Biome> registry = MinecraftServer final Registry<Biome> registry = MinecraftServer
.getServer() .getServer()
.registryAccess() .registryAccess()
.ownedRegistryOrThrow(Registry.BIOME_REGISTRY); .registryOrThrow(BIOME);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId()); ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id());
Biome biome = registry.get(resourceLocation); Biome biome = registry.get(resourceLocation);
return registry.getId(biome); return registry.getId(biome);
} }
@Override @Override
public Iterable<NamespacedKey> getRegisteredBiomes() { public Iterable<NamespacedKey> getRegisteredBiomes() {
WritableRegistry<Biome> biomeRegistry = ((CraftServer) Bukkit.getServer()) WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer())
.getServer() .getServer()
.registryAccess() .registryAccess()
.ownedRegistryOrThrow( .registryOrThrow(BIOME);
Registry.BIOME_REGISTRY);
List<ResourceLocation> keys = biomeRegistry.stream() List<ResourceLocation> keys = biomeRegistry.stream()
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); .map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
List<NamespacedKey> namespacedKeys = new ArrayList<>(); List<NamespacedKey> namespacedKeys = new ArrayList<>();
@ -674,18 +598,12 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public RelighterFactory getRelighterFactory() { public RelighterFactory getRelighterFactory() {
try { if (PaperLib.isPaper()) {
Class.forName("ca.spottedleaf.starlight.light.StarLightEngine");
if (PaperweightStarlightRelighter.isUsable()) {
return new PaperweightStarlightRelighterFactory(); return new PaperweightStarlightRelighterFactory();
} } else {
} catch (ThreadDeath td) {
throw td;
} catch (Throwable ignored) {
}
return new NMSRelighterFactory(); return new NMSRelighterFactory();
} }
}
@Override @Override
public Map<String, List<Property<?>>> getAllProperties() { public Map<String, List<Property<?>>> getAllProperties() {
@ -706,4 +624,15 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return new PaperweightPostProcessor(); return new PaperweightPostProcessor();
} }
private boolean wasAccessibleSinceLastSave(ChunkHolder holder) {
if (PaperLib.isPaper()) { // Papers new chunk system has no related replacement - therefor we assume true.
return true;
}
try {
return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder);
} catch (IllegalAccessException | InvocationTargetException ignored) {
return false;
}
}
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.math.IntPair;
@ -9,21 +9,22 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -102,7 +103,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ())); cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ));
boolean nextTick = lastTick.get() > currentTick; boolean nextTick = lastTick.get() > currentTick;
if (nextTick || cachedChanges.size() >= 1024) { if (nextTick || cachedChanges.size() >= 1024) {
if (nextTick) { if (nextTick) {
@ -132,15 +133,15 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
} }
@Override @Override
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) {
// We will assume that the tile entity was created for us, // We will assume that the tile entity was created for us,
// though we do not do this on the other versions // though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) { if (blockEntity == null) {
return false; return false;
} }
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag);
blockEntity.load((CompoundTag) nativeTag); blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess());
return true; return true;
} }
@ -157,7 +158,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
@Override @Override
public boolean isChunkTicking(LevelChunk levelChunk) { public boolean isChunkTicking(LevelChunk levelChunk) {
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
} }
@Override @Override
@ -181,7 +182,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
// Un-nest neighbour updating // Un-nest neighbour updating
for (Direction direction : NEIGHBOUR_ORDER) { for (Direction direction : NEIGHBOUR_ORDER) {
BlockPos shifted = blockPos.relative(direction); BlockPos shifted = blockPos.relative(direction);
level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); level.getBlockState(shifted).handleNeighborChanged(level, shifted, oldState.getBlock(), blockPos, false);
} }
} }
if (newState.hasAnalogOutputSignal()) { if (newState.hasAnalogOutputSignal()) {
@ -217,6 +218,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,
@ -246,7 +253,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };
@ -262,7 +269,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
} }
} }
}; };

Datei anzeigen

@ -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_21_R1;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -7,35 +7,37 @@ import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
@ -43,7 +45,6 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.HashMapPalette; import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
@ -51,18 +52,27 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette; import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinFloatTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTagType;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.AbstractSet; import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -72,40 +82,49 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
private static final Function<BlockEntity, CompoundTag> nmsTile2We = public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize( .getInstance()
() -> tileEntity.save(new net.minecraft.nbt.CompoundTag()))); .getBukkitImplAdapter()).blockEntityToCompoundTag();
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
.getInstance() .getInstance()
.getBukkitImplAdapter()); .getBukkitImplAdapter());
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
private final ReentrantLock callLock = new ReentrantLock();
private final ServerLevel serverLevel; private final ServerLevel serverLevel;
private final int chunkX; private final int chunkX;
private final int chunkZ; private final int chunkZ;
private final IntPair chunkPos;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
private final int minSectionPosition; private final int minSectionPosition;
private final int maxSectionPosition; private final int maxSectionPosition;
private final Registry<Biome> biomeRegistry;
private final IdMap<Holder<Biome>> biomeHolderIdMap;
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
private final Object sendLock = new Object();
private LevelChunkSection[] sections; private LevelChunkSection[] sections;
private LevelChunk levelChunk; private LevelChunk levelChunk;
private DataLayer[] blockLight; private DataLayer[] blockLight;
private DataLayer[] skyLight; private DataLayer[] skyLight;
private boolean createCopy = false; private boolean createCopy = false;
private PaperweightGetBlocks_Copy copy = null;
private boolean forceLoadSections = true; private boolean forceLoadSections = true;
private boolean lightUpdate = false; private boolean lightUpdate = false;
private int copyKey = 0;
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ); this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -122,6 +141,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.maxSectionPosition = maxHeight >> 4; this.maxSectionPosition = maxHeight >> 4;
this.skyLight = new DataLayer[getSectionCount()]; this.skyLight = new DataLayer[getSectionCount()];
this.blockLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()];
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
this.chunkPos = new IntPair(chunkX, chunkZ);
} }
public int getChunkX() { public int getChunkX() {
@ -138,13 +160,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
}
this.createCopy = createCopy; this.createCopy = createCopy;
// Increment regardless of whether copy will be created or not to return null from getCopy()
return ++this.copyKey;
} }
@Override @Override
public IChunkGet getCopy() { public IChunkGet getCopy(final int key) {
return copy; return copies.remove(key);
}
@Override
public void lockCall() {
this.callLock.lock();
}
@Override
public void unlockCall() {
this.callLock.unlock();
} }
@Override @Override
@ -193,19 +230,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
ChunkBiomeContainer index = getChunk().getBiomes(); LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()];
Biome biomes = null; Holder<Biome> biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2);
if (y == -1) { return PaperweightPlatformAdapter.adapt(biomes, serverLevel);
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;
} }
@Override @Override
@ -216,12 +243,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (dataLayer != null) { if (dataLayer != null) {
lightUpdate = true; lightUpdate = true;
synchronized (dataLayer) { synchronized (dataLayer) {
byte[] bytes = PaperLib.isPaper() ? dataLayer.getIfSet() : dataLayer.getData(); byte[] bytes = dataLayer.getData();
if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) {
Arrays.fill(bytes, (byte) 0); Arrays.fill(bytes, (byte) 0);
} }
} }
}
if (sky) { if (sky) {
SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer);
DataLayer dataLayer1 = serverLevel DataLayer dataLayer1 = serverLevel
@ -232,33 +257,32 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (dataLayer1 != null) { if (dataLayer1 != null) {
lightUpdate = true; lightUpdate = true;
synchronized (dataLayer1) { synchronized (dataLayer1) {
byte[] bytes = PaperLib.isPaper() ? dataLayer1.getIfSet() : dataLayer1.getData(); byte[] bytes = dataLayer1.getData();
if (!PaperLib.isPaper() || bytes != DataLayer.EMPTY_NIBBLE) {
Arrays.fill(bytes, (byte) 0); Arrays.fill(bytes, (byte) 0);
} }
} }
} }
} }
}
@Override @Override
public CompoundTag getTile(int x, int y, int z) { public FaweCompoundTag tile(final int x, final int y, final int z) {
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
chunkX << 4), y, (z & 15) + ( chunkX << 4), y, (z & 15) + (
chunkZ << 4))); chunkZ << 4)));
if (blockEntity == null) { if (blockEntity == null) {
return null; return null;
} }
return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))); return NMS_TO_TILE.apply(blockEntity);
} }
@Override @Override
public Map<BlockVector3, CompoundTag> getTiles() { public Map<BlockVector3, FaweCompoundTag> tiles() {
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities(); Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
if (nmsTiles.isEmpty()) { if (nmsTiles.isEmpty()) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
} }
@Override @Override
@ -278,8 +302,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
LightLayer.BLOCK, LightLayer.BLOCK,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
skyLight[alayer] = dataLayer; skyLight[alayer] = dataLayer;
@ -306,7 +329,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
Arrays.fill(LAYER_COUNT, (byte) 15); Arrays.fill(LAYER_COUNT, (byte) 15);
dataLayer = new DataLayer(LAYER_COUNT); dataLayer = new DataLayer(LAYER_COUNT);
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos,
dataLayer, true dataLayer
); );
} }
blockLight[alayer] = dataLayer; blockLight[alayer] = dataLayer;
@ -322,14 +345,22 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
Entity entity = serverLevel.getEntity(uuid); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
Entity entity = null;
for (Entity e : entities) {
if (e.getUUID().equals(uuid)) {
entity = e;
break;
}
}
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
} }
for (CompoundTag tag : getEntities()) { for (FaweCompoundTag tag : entities()) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -337,13 +368,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
if (entities.isEmpty()) { if (entities.isEmpty()) {
return Collections.emptySet(); return Collections.emptyList();
} }
int size = entities.size(); int size = entities.size();
return new AbstractSet<>() { return new AbstractCollection<>() {
@Override @Override
public int size() { public int size() {
return size; return size;
@ -356,10 +388,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public boolean contains(Object get) { public boolean contains(Object get) {
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof FaweCompoundTag getTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); UUID getUUID = NbtUtils.uuid(getTag);
for (Entity entity : entities) { for (Entity entity : entities) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
@ -371,15 +403,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Nonnull @Nonnull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<FaweCompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); CompoundTag tag = new CompoundTag();
input.save(tag); input.save(tag);
return (CompoundTag) adapter.toNative(tag); return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
}).collect(Collectors.toList()); })::iterator;
return result.iterator(); return result.iterator();
} }
}; };
} }
private void removeEntity(Entity entity) { private void removeEntity(Entity entity) {
@ -393,13 +426,19 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
if (!callLock.isHeldByCurrentThread()) {
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
}
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
if (createCopy) {
if (copies.containsKey(copyKey)) {
throw new IllegalStateException("Copy key already used.");
}
copies.put(copyKey, copy);
}
try { 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 // Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
List<BlockEntity> beacons = null; List<BlockEntity> beacons = null;
@ -432,18 +471,79 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} }
final BiomeType[][] biomes = set.getBiomes();
int bitMask = 0; int bitMask = 0;
synchronized (nmsChunk) { synchronized (nmsChunk) {
LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); LevelChunkSection[] levelChunkSections = nmsChunk.getSections();
for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) {
int getSectionIndex = layerNo - getMinSectionPosition();
int setSectionIndex = layerNo - set.getMinSectionPosition();
if (!set.hasSection(layerNo)) { if (!set.hasSection(layerNo)) {
// No blocks, but might be biomes present. Handle this lazily.
if (biomes == null) {
continue; continue;
} }
int layer = layerNo - getMinSectionPosition(); 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());
}
bitMask |= 1 << layer; if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
biomes[setSectionIndex],
biomeHolderIdMap
);
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo,
new char[4096],
adapter,
biomeRegistry,
biomeData
);
if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections,
null,
newSection,
getSectionIndex
)) {
updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex);
continue;
} else {
existingSection = levelChunkSections[getSectionIndex];
if (existingSection == null) {
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
getSectionIndex
);
continue;
}
}
} else {
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (paletteBiomes != null) {
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
}
}
}
}
continue;
}
bitMask |= 1 << getSectionIndex;
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to // 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. // this chunk GET when #updateGet is called. Future dords, please listen this time.
@ -453,45 +553,61 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
// synchronise on internal section to avoid circular locking with a continuing edit if the chunk was // 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. // submitted to keep loaded internal chunks to queue target size.
synchronized (super.sectionLocks[layer]) { synchronized (super.sectionLocks[getSectionIndex]) {
LevelChunkSection newSection;
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
// Don't attempt to tick section whilst we're editing
if (existingSection != null) {
PaperweightPlatformAdapter.clearCounts(existingSection);
}
if (createCopy) { if (createCopy) {
char[] tmpLoad = loadPrivately(layerNo); char[] tmpLoad = loadPrivately(layerNo);
char[] copyArr = new char[4096]; char[] copyArr = new char[4096];
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
copy.storeSection(layer, copyArr); copy.storeSection(getSectionIndex, copyArr);
} if (biomes != null && existingSection != null) {
copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
LevelChunkSection newSection;
LevelChunkSection existingSection = levelChunkSections[layer];
// Don't attempt to tick section whilst we're editing
if (existingSection != null) {
PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
} }
} }
if (existingSection == null) { if (existingSection == null) {
newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter); PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) { biomeHolderIdMap,
updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo,
setArr,
adapter,
biomeRegistry,
biomeData
);
if (PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections,
null,
newSection,
getSectionIndex
)) {
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
continue; continue;
} else { } else {
existingSection = levelChunkSections[layer]; existingSection = levelChunkSections[getSectionIndex];
if (existingSection == null) { if (existingSection == null) {
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
+layer getSectionIndex
); );
continue; 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); PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
// Synchronize to prevent further acquisitions // Synchronize to prevent further acquisitions
@ -504,10 +620,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.levelChunk = nmsChunk; this.levelChunk = nmsChunk;
this.sections = null; this.sections = null;
this.reset(); this.reset();
} else if (existingSection != getSections(false)[layer]) { } else if (existingSection != getSections(false)[getSectionIndex]) {
this.sections[layer] = existingSection; this.sections[getSectionIndex] = existingSection;
this.reset(); 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); this.reset(layerNo);
/*} else if (lock.isModified()) { /*} else if (lock.isModified()) {
this.reset(layerNo);*/ this.reset(layerNo);*/
@ -515,56 +634,34 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} finally { } finally {
sectionLock.writeLock().unlock(); sectionLock.writeLock().unlock();
} }
newSection =
PaperweightPlatformAdapter.newChunkSection( PalettedContainer<Holder<Biome>> biomeData = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
this::loadPrivately, this::loadPrivately,
setArr, setArr,
fastmode, adapter,
adapter biomeRegistry,
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
); );
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
serverLevel.getWorld().getName(),
chunkPos,
levelChunkSections, levelChunkSections,
existingSection, existingSection,
newSection, newSection,
layer getSectionIndex
)) { )) {
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
+layer getSectionIndex
); );
} else { } else {
updateGet(nmsChunk, levelChunkSections, newSection, setArr, layer); updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
}
}
}
}
// 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);
}
}
} }
} }
} }
@ -628,7 +725,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) { for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid); Entity entity = serverLevel.getEntities().get(uuid);
if (entity != null) { if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
@ -640,48 +737,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
}; };
} }
Set<CompoundTag> entities = set.getEntities(); Collection<FaweCompoundTag> entities = set.entities();
if (entities != null && !entities.isEmpty()) { if (entities != null && !entities.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[2]; syncTasks = new Runnable[2];
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); Iterator<FaweCompoundTag> iterator = entities.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final CompoundTag nativeTag = iterator.next(); final FaweCompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final LinCompoundTag linTag = nativeTag.linTag();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
if (idTag == null || posTag == null || rotTag == null) { if (idTag == null || posTag == null || rotTag == null) {
LOGGER.error("Unknown entity tag: {}", nativeTag); LOGGER.error("Unknown entity tag: {}", nativeTag);
continue; continue;
} }
final double x = posTag.getDouble(0); final double x = posTag.get(0).valueAsDouble();
final double y = posTag.getDouble(1); final double y = posTag.get(1).valueAsDouble();
final double z = posTag.getDouble(2); final double z = posTag.get(2).valueAsDouble();
final float yaw = rotTag.getFloat(0); final float yaw = rotTag.get(0).valueAsFloat();
final float pitch = rotTag.getFloat(1); final float pitch = rotTag.get(1).valueAsFloat();
final String id = idTag.getValue(); final String id = idTag.value();
EntityType<?> type = EntityType.byString(id).orElse(null); EntityType<?> type = EntityType.byString(id).orElse(null);
if (type != null) { if (type != null) {
Entity entity = type.create(nmsWorld); Entity entity = type.create(serverLevel);
if (entity != null) { if (entity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); entity.setUUID(NbtUtils.uuid(nativeTag));
if (!nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn( LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`", "Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id, id,
nmsWorld.getWorld().getName(), serverLevel.getWorld().getName(),
x, x,
y, y,
z z
@ -696,34 +792,33 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
// set tiles // set tiles
Map<BlockVector3, CompoundTag> tiles = set.getTiles(); Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
if (tiles != null && !tiles.isEmpty()) { if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) { if (syncTasks == null) {
syncTasks = new Runnable[1]; syncTasks = new Runnable[1];
} }
syncTasks[0] = () -> { syncTasks[0] = () -> {
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) { for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue(); final FaweCompoundTag nativeTag = entry.getValue();
final BlockVector3 blockHash = entry.getKey(); final BlockVector3 blockHash = entry.getKey();
final int x = blockHash.getX() + bx; final int x = blockHash.x() + bx;
final int y = blockHash.getY(); final int y = blockHash.y();
final int z = blockHash.getZ() + bz; final int z = blockHash.z() + bz;
final BlockPos pos = new BlockPos(x, y, z); final BlockPos pos = new BlockPos(x, y, z);
synchronized (nmsWorld) { synchronized (serverLevel) {
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
if (tileEntity == null || tileEntity.isRemoved()) { if (tileEntity == null || tileEntity.isRemoved()) {
nmsWorld.removeBlockEntity(pos); serverLevel.removeBlockEntity(pos);
tileEntity = nmsWorld.getBlockEntity(pos); tileEntity = serverLevel.getBlockEntity(pos);
} }
if (tileEntity != null) { if (tileEntity != null) {
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
nativeTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
tileEntity.load(tag); tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess());
} }
} }
} }
@ -735,15 +830,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
callback = null; callback = null;
} else { } else {
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
boolean finalLightUpdate = lightUpdate;
callback = () -> { callback = () -> {
// Set Modified // Set Modified
nmsChunk.setLightCorrect(true); // Set Modified nmsChunk.setLightCorrect(true); // Set Modified
nmsChunk.mustNotSave = false; nmsChunk.mustNotSave = false;
nmsChunk.markUnsaved(); nmsChunk.setUnsaved(true);
// send to player // send to player
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
this.send(finalMask, finalLightUpdate); this.send();
} }
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); finalizer.run();
@ -765,7 +859,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -831,9 +925,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (super.sections[layer] != null) { if (super.sections[layer] != null) {
synchronized (super.sectionLocks[layer]) { synchronized (super.sectionLocks[layer]) {
if (super.sections[layer].isFull() && super.blocks[layer] != null) { if (super.sections[layer].isFull() && super.blocks[layer] != null) {
char[] blocks = new char[4096]; return super.blocks[layer];
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
return blocks;
} }
} }
} }
@ -841,8 +933,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send() {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
}
} }
/** /**
@ -879,11 +973,18 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
try { try {
lock.acquire(); lock.acquire();
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); final PalettedContainer<BlockState> blocks = section.getStates();
final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(blocks); final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks);
final Palette<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.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<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.get(dataObject);
final int bitsPerEntry = bits.getBits();
final long[] blockStates = bits.getRaw(); final long[] blockStates = bits.getRaw();
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data);
@ -936,7 +1037,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) { if (ibd == null) {
return BlockTypesCache.ReservedIDs.AIR; return BlockTypesCache.ReservedIDs.AIR;
} else { } else {
@ -946,9 +1047,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
public LevelChunkSection[] getSections(boolean force) { public LevelChunkSection[] getSections(boolean force) {
force &= forceLoadSections; force &= forceLoadSections;
sectionLock.readLock().lock();
LevelChunkSection[] tmp = sections; LevelChunkSection[] tmp = sections;
sectionLock.readLock().unlock();
if (tmp == null || force) { if (tmp == null || force) {
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
@ -994,8 +1093,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
lightLayer, lightLayer,
sectionPos, sectionPos,
dataLayer, dataLayer
true
); );
} }
synchronized (dataLayer) { synchronized (dataLayer) {
@ -1013,6 +1111,36 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
private PalettedContainer<Holder<Biome>> setBiomesToPalettedContainer(
final BiomeType[][] biomes,
final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data
) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData = data.recreate();
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) {
biomeData.set(x, y, z, data.get(x, y, z));
} else {
biomeData.set(
x,
y,
z,
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
);
}
}
}
}
return biomeData;
}
@Override @Override
public boolean hasSection(int layer) { public boolean hasSection(int layer) {
layer -= getMinSectionPosition(); layer -= getMinSectionPosition();
@ -1041,10 +1169,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
LevelChunkSection existing = getSections(true)[layer]; LevelChunkSection existing = getSections(true)[layer];
try { try {
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocksExisting = existing.getStates(); final PalettedContainer<BlockState> blocksExisting = existing.getStates();
final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting);
final Palette<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.get( final Palette<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.get(
blocksExisting); dataObject);
int paletteSize; int paletteSize;
if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { if (palette instanceof LinearPalette || palette instanceof HashMapPalette) {

Datei anzeigen

@ -1,27 +1,36 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers; import com.fastasyncworldedit.core.util.NbtUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; 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.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import net.minecraft.core.Holder;
import net.minecraft.nbt.Tag;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; 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.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -31,14 +40,16 @@ import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet { public class PaperweightGetBlocks_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Set<CompoundTag> entities = new HashSet<>();
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
private final Set<FaweCompoundTag> entities = new HashSet<>();
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; final ServerLevel serverLevel;
final LevelChunk levelChunk; final LevelChunk levelChunk;
private ChunkBiomeContainer chunkBiomeContainer; private Holder<Biome>[][] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk; this.levelChunk = levelChunk;
@ -49,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
protected void storeTile(BlockEntity blockEntity) { protected void storeTile(BlockEntity blockEntity) {
@SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
tiles.put( tiles.put(
BlockVector3.at( BlockVector3.at(
blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ() blockEntity.getBlockPos().getZ()
), ),
new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.save(new net.minecraft.nbt.CompoundTag()))) FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId(DedicatedServer
.getServer()
.registryAccess())))
); );
} }
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); @SuppressWarnings("unchecked")
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag)); entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
} }
@Override @Override
public Set<CompoundTag> getEntities() { public Collection<FaweCompoundTag> entities() {
return this.entities; return this.entities;
} }
@Override @Override
public CompoundTag getEntity(UUID uuid) { public @Nullable FaweCompoundTag entity(final UUID uuid) {
for (CompoundTag tag : entities) { for (FaweCompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { if (uuid.equals(NbtUtils.uuid(tag))) {
return tag; return tag;
} }
} }
@ -99,7 +103,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -134,28 +139,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return minHeight >> 4; 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 @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
Biome biome = null; Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
if (y == -1) { return PaperweightPlatformAdapter.adapt(biome, serverLevel);
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;
} }
@Override @Override
@ -181,10 +168,40 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
blocks[layer] = data; blocks[layer] = data;
} }
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) {
biomes = new Holder[getSectionCount()][];
}
if (biomes[layer] == null) {
biomes[layer] = new Holder[64];
}
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
if (PaperLib.isPaper()) {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
}
} else {
try {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} else {
LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}",
PalettedContainer.class.getSimpleName(),
biomeData.getClass().getSimpleName()
);
}
}
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)]; BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z); return state.toBaseBlock((IBlocks) this, x, y, z);
} }
@Override @Override
@ -196,6 +213,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public char[] load(int layer) { public char[] load(int layer) {
layer -= getMinSectionPosition(); layer -= getMinSectionPosition();
if (blocks[layer] == null) {
blocks[layer] = new char[4096];
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
}
return blocks[layer]; return blocks[layer];
} }
@ -210,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return BlockTypesCache.states[get(x, y, z)]; return BlockTypesCache.states[get(x, y, z)];
} }
@Override
public Map<BlockVector3, FaweCompoundTag> tiles() {
return tiles;
}
@Override
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@Override @Override
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
return 0; return 0;

Datei anzeigen

@ -0,0 +1,34 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
//TODO un-very-break-this
public class PaperweightMapChunkUtil extends MapChunkUtil<ClientboundLevelChunkWithLightPacket> {
public PaperweightMapChunkUtil() throws NoSuchFieldException {
fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a"));
fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "b"));
fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "c"));
fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b"));
fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "d"));
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();
}
}

Datei anzeigen

@ -1,13 +1,15 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
@ -24,11 +26,11 @@ import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ThreadingDetector;
@ -36,11 +38,13 @@ import net.minecraft.util.Unit;
import net.minecraft.util.ZeroBitStorage; import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette; import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
@ -49,15 +53,17 @@ import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette; import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -77,6 +83,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.function.Function; 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 final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldData; public static final Field fieldData;
@ -88,27 +97,33 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector; private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock; private static final Field fieldLock;
private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity; 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 Field fieldRemove;
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER;
static final MethodHandle PALETTED_CONTAINER_GET;
static { static {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
try { try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
fieldData.setAccessible(true); fieldData.setAccessible(true);
@ -122,79 +137,104 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true); fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g"));
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); Field tmpFieldBiomes;
fieldNonEmptyBlockCount.setAccessible(true); try {
// Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf
} catch (NoSuchFieldException ignored) {
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf
}
fieldBiomes = tmpFieldBiomes;
fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
"b" "b"
), long.class); ), long.class);
getVisibleChunkIfPresent.setAccessible(true); getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) { if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetector.setAccessible(true);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); fieldLock.setAccessible(true);
} else { } else {
// in paper, the used methods are synchronized properly // in paper, the used methods are synchronized properly
fieldThreadingDetector = null; fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null; fieldLock = null;
fieldLockOffset = -1;
} }
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
Refraction.pickName("removeGameEventListener", "d"), Refraction.pickName("removeGameEventListener", "a"),
BlockEntity.class BlockEntity.class,
ServerLevel.class
); );
removeGameEventListener.setAccessible(true); removeGameEventListener.setAccessible(true);
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener); methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName( Refraction.pickName(
"removeBlockEntityTicker", "removeBlockEntityTicker",
"l" "k"
), BlockPos.class ), BlockPos.class
); );
removeBlockEntityTicker.setAccessible(true); removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker); methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true); fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); try {
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); Level.class.getDeclaredMethod("moonrise$getEntityLookup");
if ((scale & (scale - 1)) != 0) { PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities");
throw new Error("data type scale not a power of two"); PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true);
} catch (NoSuchMethodException ignored) {
// Non-Paper
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} }
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (RuntimeException e) { Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
Refraction.pickName("get", "a"),
int.class
);
palettedContaienrGet.setAccessible(true);
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
} catch (RuntimeException | Error e) {
throw e; throw e;
} catch (Throwable rethrow) { } catch (Exception e) {
rethrow.printStackTrace(); throw new RuntimeException(e);
throw new RuntimeException(rethrow);
} }
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( static boolean setSectionAtomic(
String worldName,
IntPair pair,
LevelChunkSection[] sections, LevelChunkSection[] sections,
LevelChunkSection expected, LevelChunkSection expected,
LevelChunkSection value, LevelChunkSection value,
int layer int layer
) { ) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
} }
// There is no point in having a functional semaphore for paper servers. // There is no point in having a functional semaphore for paper servers.
@ -207,19 +247,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks);
blocks,
fieldThreadingDetectorOffset
);
synchronized (currentThreadingDetector) { synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) { if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore; return delegateSemaphore;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); fieldLock.set(currentThreadingDetector, newLock);
return newLock; return newLock;
} }
} }
@ -270,7 +306,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!"); throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
} }
} }
return chunk.getHandle(); addTicket(serverLevel, chunkX, chunkZ);
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -280,9 +317,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) { private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket // Ensure chunk is definitely loaded before applying a ticket
net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource() .getChunkSource()
.addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); .addRegionTicket(ChunkHolderManager.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
} }
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
@ -295,27 +332,29 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) { if (chunkHolder == null) {
return; return;
} }
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ); ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
// UNLOADED_CHUNK LevelChunk levelChunk;
Optional<LevelChunk> optional = ((Either) chunkHolder
.getTickingChunkFuture()
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
// getChunkAtIfLoadedImmediately is paper only // getChunkAtIfLoadedImmediately is paper only
optional = optional.or(() -> Optional.ofNullable(nmsWorld levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
.getChunkSource() } else {
.getChunkAtIfLoadedImmediately(chunkX, chunkZ))); levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
} }
if (optional.isEmpty()) { if (levelChunk == null) {
return; return;
} }
LevelChunk levelChunk = optional.get(); StampLockHolder lockHolder = new StampLockHolder();
TaskManager.taskManager().task(() -> { NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
if (lockHolder.chunkLock == null) {
return;
}
MinecraftServer.getServer().execute(() -> {
try {
ClientboundLevelChunkWithLightPacket packet; ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket( packet = new ClientboundLevelChunkWithLightPacket(
@ -323,7 +362,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
null, null,
null, null,
true,
false // last false is to not bother with x-ray false // last false is to not bother with x-ray
); );
} else { } else {
@ -332,11 +370,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
levelChunk, levelChunk,
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
null, null,
null, null
true
); );
} }
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
} finally {
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
}
}); });
} }
@ -366,7 +406,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -439,12 +479,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
.getBukkitImplAdapter() .getBukkitImplAdapter()
.getInternalBiomeId( .getInternalBiomeId(
BiomeTypes.PLAINS)), BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES
null
); );
} }
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes); return new LevelChunkSection(blockStatePalettedContainer, biomes);
} catch (final Throwable e) { } catch (final Throwable e) {
throw e; throw e;
} finally { } finally {
@ -457,20 +496,26 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (biomes == null) { if (biomes == null) {
return new LevelChunkSection(layer, biomeRegistry); return new LevelChunkSection(biomeRegistry);
} }
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>( PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY, Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(), Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES, PalettedContainer.Strategy.SECTION_STATES
null
); );
return new LevelChunkSection(layer, dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
}
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
} }
/** /**
@ -507,8 +552,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry, biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES
null
); );
final Palette<Holder<Biome>> biomePalette; final Palette<Holder<Biome>> biomePalette;
@ -586,7 +630,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) { public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY); final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME);
if (biomeRegistry.getKey(biome.value()) == null) { if (biomeRegistry.getKey(biome.value()) == null) {
return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN
: null; : null;
@ -594,16 +638,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString());
} }
@SuppressWarnings("unchecked")
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try { try {
// Do the method ourselves to avoid trying to reflect generic method parameters
// similar to removeGameEventListener
if (levelChunk.loaded || levelChunk.level.isClientSide()) { if (levelChunk.loaded || levelChunk.level.isClientSide()) {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) { if (blockEntity != null) {
if (!levelChunk.level.isClientSide) { if (!levelChunk.level.isClientSide) {
methodRemoveGameEventListener.invoke(levelChunk, beacon); methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level);
} }
fieldRemove.set(beacon, true); fieldRemove.set(beacon, true);
} }
@ -615,7 +656,22 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
static List<Entity> getEntities(LevelChunk chunk) { static List<Entity> getEntities(LevelChunk chunk) {
return chunk.level.entityManager.getEntities(chunk.getPos()); if (PaperLib.isPaper()) {
try {
//noinspection unchecked
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level
.moonrise$getEntityLookup()
.getChunk(chunk.locX, chunk.locZ));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Failed to lookup entities [PAPER=true]", e);
}
}
try {
//noinspection unchecked
return ((PersistentEntitySectionManager<Entity>) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos());
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to lookup entities [PAPER=false]", e);
}
} }
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> { record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {

Datei anzeigen

@ -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_21_R1;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
@ -165,7 +165,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
} else { } else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
} }
serverLevel.getLiquidTicks().scheduleTick( serverLevel.scheduleTick(
position, position,
type, type,
type.getTickDelay(serverLevel) type.getTickDelay(serverLevel)

Datei anzeigen

@ -0,0 +1,80 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.status.ChunkPyramid;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLevel, ChunkPos> {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkPyramid.LOADING_PYRAMID
.getStepTo(ChunkStatus.FULL)
.getAccumulatedRadiusOf(ChunkStatus.LIGHT);
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<?> queue) {
super(serverLevel, queue);
}
@Override
protected ChunkPos createChunkPos(final long chunkKey) {
return new ChunkPos(chunkKey);
}
@Override
protected long asLong(final int chunkX, final int chunkZ) {
return ChunkPos.asLong(chunkX, chunkZ);
}
@Override
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
chunkPos,
LIGHT_LEVEL,
Unit.INSTANCE
));
}
protected void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().starlight$serverRelightChunks(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
protected void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen