geforkt von Mirrors/FastAsyncWorldEdit
Merge remote-tracking branch 'upstream/main'
# Conflicts: # build.gradle.kts # settings.gradle.kts # worldedit-bukkit/build.gradle.kts
Dieser Commit ist enthalten in:
Commit
32e2ba6970
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -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
|
||||||
|
|
||||||
|
36
.github/renovate.json
vendored
36
.github/renovate.json
vendored
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"$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" : [
|
||||||
@ -29,7 +30,34 @@
|
|||||||
"org.spongepowered:spongeapi",
|
"org.spongepowered:spongeapi",
|
||||||
"org.yaml:snakeyaml"
|
"org.yaml:snakeyaml"
|
||||||
],
|
],
|
||||||
"labels": ["Renovate"],
|
"labels" : [
|
||||||
|
"Renovate"
|
||||||
|
],
|
||||||
"rebaseWhen" : "conflicted",
|
"rebaseWhen" : "conflicted",
|
||||||
"schedule": ["on the first day of the month"]
|
"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+)$"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -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>"
|
||||||
|
10
.github/workflows/build-pr.yml
vendored
10
.github/workflows/build-pr.yml
vendored
@ -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
|
||||||
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -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 }}
|
||||||
|
12
.github/workflows/codeql.yml
vendored
12
.github/workflows/codeql.yml
vendored
@ -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
|
||||||
|
23
.github/workflows/label-merge-conflicts.yaml
vendored
Normale Datei
23
.github/workflows/label-merge-conflicts.yaml
vendored
Normale Datei
@ -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
|
2
.github/workflows/release-drafter.yml
vendored
2
.github/workflows/release-drafter.yml
vendored
@ -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 }}
|
||||||
|
12
.github/workflows/upload-release-assets.yml
vendored
12
.github/workflows/upload-release-assets.yml
vendored
@ -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 }}
|
||||||
|
@ -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
2
Jenkinsfile
vendored
@ -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'
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,8 @@ fun Project.applyPaperweightAdapterConfiguration() {
|
|||||||
tasks.named("assemble") {
|
tasks.named("assemble") {
|
||||||
dependsOn("reobfJar")
|
dependsOn("reobfJar")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named("javadoc") {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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}"
|
||||||
|
@ -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 {
|
||||||
|
@ -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-", "")}"))
|
||||||
|
@ -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
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binäre Datei nicht angezeigt.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
22
gradlew
vendored
@ -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
22
gradlew.bat
vendored
@ -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
|
||||||
|
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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)
|
||||||
}
|
}
|
@ -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");
|
@ -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;
|
@ -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
|
@ -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();
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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) {
|
@ -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;
|
@ -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;
|
@ -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.
|
||||||
*/
|
*/
|
@ -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;
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
@ -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();
|
@ -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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
@ -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");
|
@ -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) {
|
@ -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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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();
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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);
|
||||||
}
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
@ -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();
|
@ -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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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-Diff unterdrückt, da er zu groß ist
Diff laden
@ -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,7 +2339,6 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
|
|||||||
|
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DataConverterShulkerBoxItem implements DataConverter {
|
private static class DataConverterShulkerBoxItem implements DataConverter {
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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
|
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
@ -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);
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
@ -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();
|
@ -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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts
Normale Datei
17
worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts
Normale Datei
@ -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-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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"
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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) {
|
@ -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;
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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> {
|
@ -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)
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,23 +1,20 @@
|
|||||||
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.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_17_R1.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;
|
||||||
@ -26,4 +23,3 @@ public class PaperweightStarlightRelighterFactory implements RelighterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren