geforkt von Mirrors/FastAsyncWorldEdit
Merge remote-tracking branch 'upstream/main'
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Dieser Commit ist enthalten in:
Commit
c0f935ef55
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -8,7 +8,7 @@ body:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report for FastAsyncWorldEdit! Fill out the following form to your best ability to help us fix the problem.
|
||||
Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/fastasyncworldedit-documentation/).
|
||||
Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://forms.gle/btgdRn9yhGtzEiGW8) form!
|
||||
Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://github.com/IntellectualSites/FastAsyncWorldEdit/security/policy) GitHub form!
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
@ -27,14 +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.
|
||||
multiple: false
|
||||
options:
|
||||
- '1.20.1'
|
||||
- '1.20'
|
||||
- '1.19.4'
|
||||
- '1.19.3'
|
||||
- '1.19.2'
|
||||
- '1.19.1'
|
||||
- '1.19'
|
||||
- '1.18.2'
|
||||
- '1.17.1'
|
||||
- '1.16.5'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
12
.github/renovate.json
vendored
12
.github/renovate.json
vendored
@ -4,6 +4,7 @@
|
||||
"config:base",
|
||||
":semanticCommitsDisabled"
|
||||
],
|
||||
"automerge": true,
|
||||
"ignoreDeps": [
|
||||
"guava",
|
||||
"com.google.guava:guava",
|
||||
@ -18,10 +19,15 @@
|
||||
"net.fabricmc:fabric-loader",
|
||||
"net.fabricmc.fabric-api:fabric-api",
|
||||
"com.github.luben:zstd-jni",
|
||||
"net.kyori",
|
||||
"net.kyori:adventure-nbt",
|
||||
"org.jetbrains.kotlin.jvm",
|
||||
"log4j"
|
||||
"log4j",
|
||||
"org.apache.logging.log4j:log4j-api",
|
||||
"org.apache.logging.log4j:log4j-bom",
|
||||
"org.apache.logging.log4j:log4j-slf4j-impl",
|
||||
"org.apache.logging.log4j:log4j-core",
|
||||
"org.bstats:bstats-sponge",
|
||||
"org.spongepowered:spongeapi",
|
||||
"org.yaml:snakeyaml"
|
||||
],
|
||||
"labels": ["Renovate"],
|
||||
"rebaseWhen": "conflicted",
|
||||
|
@ -13,7 +13,7 @@ jobs:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
DISCORD_USERNAME: FastAsyncWorldEdit Release
|
||||
DISCORD_AVATAR: https://raw.githubusercontent.com/IntellectualSites/Assets/main/plugins/FastAsyncWorldEdit/FastAsyncWorldEdit.png
|
||||
uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # ratchet:Ilshidur/action-discord@0.3.2
|
||||
uses: Ilshidur/action-discord@0.3.2
|
||||
with:
|
||||
args: |
|
||||
"<@&525015715300900875> <@&706463154804097105> <@&671372968462516240>"
|
||||
|
8
.github/workflows/build-pr.yml
vendored
8
.github/workflows/build-pr.yml
vendored
@ -16,6 +16,12 @@ jobs:
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
cache: gradle
|
||||
java-version: 17
|
||||
- name: Build on ${{ matrix.os }}
|
||||
run: ./gradlew clean build
|
||||
run: ./gradlew build -s
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: FastAsyncWorldEdit-SNAPSHOT
|
||||
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar
|
||||
|
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@ -76,18 +76,3 @@ jobs:
|
||||
run: ./gradlew modrinth
|
||||
env:
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
- name: Publish to CurseForge
|
||||
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
|
||||
uses: itsmeow/curseforge-upload@v3
|
||||
with:
|
||||
file_path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-${{ github.event.release.tag_name }}.jar
|
||||
# https://minecraft.curseforge.com/api/game/versions?token=redacted
|
||||
# gameVersionTypeID: 1
|
||||
game_versions: "8503,9016,9190,9261,9560,9561"
|
||||
project_id: 103525
|
||||
game_endpoint: minecraft
|
||||
token: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||
display_name: FastAsyncWorldEdit ${{ github.event.release.tag_name }}
|
||||
release_type: release
|
||||
changelog: "Click here to view changelog: https://github.com/IntellectualSites/FastAsyncWorldEdit/releases/tag/${{ github.event.release.tag_name }}"
|
||||
changelog_type: markdown
|
||||
|
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@ -1,5 +1,7 @@
|
||||
name: "CodeQL"
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [main]
|
||||
@ -18,6 +20,12 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
cache: gradle
|
||||
java-version: 17
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,3 +33,5 @@ worldedit-core/src/main/resources/lang/*
|
||||
/worldedit-core/.factorypath
|
||||
|
||||
.DS_Store
|
||||
### Run server ignore
|
||||
run-*
|
||||
|
11
Jenkinsfile
vendored
11
Jenkinsfile
vendored
@ -4,14 +4,13 @@ pipeline {
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
stages {
|
||||
stage('Set JDK 17') {
|
||||
steps {
|
||||
tool name: 'Temurin-17.0.6+10', type: 'jdk'
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './gradlew clean build'
|
||||
withEnv([
|
||||
"PATH+JAVA=${tool 'Temurin-17.0.7_7'}/bin"
|
||||
]) {
|
||||
sh './gradlew clean build'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Archive artifacts') {
|
||||
|
@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer
|
||||
|
||||
plugins {
|
||||
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
|
||||
id("xyz.jpenilla.run-paper") version "2.0.1"
|
||||
id("xyz.jpenilla.run-paper") version "2.1.0"
|
||||
}
|
||||
|
||||
if (!File("$rootDir/.git").exists()) {
|
||||
@ -34,7 +34,7 @@ logger.lifecycle("""
|
||||
*******************************************
|
||||
""")
|
||||
|
||||
var rootVersion by extra("2.6.0")
|
||||
var rootVersion by extra("2.7.1")
|
||||
var snapshot by extra("SNAPSHOT")
|
||||
var revision: String by extra("")
|
||||
var buildNumber by extra("")
|
||||
@ -83,7 +83,7 @@ allprojects {
|
||||
}
|
||||
|
||||
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")
|
||||
val supportedVersions = listOf("1.17.1", "1.18.2", "1.19.4", "1.20", "1.20.1")
|
||||
|
||||
tasks {
|
||||
supportedVersions.forEach {
|
||||
@ -97,7 +97,7 @@ tasks {
|
||||
}
|
||||
}
|
||||
runServer {
|
||||
minecraftVersion("1.19.3")
|
||||
minecraftVersion("1.20.1")
|
||||
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
||||
.toTypedArray())
|
||||
|
||||
@ -105,7 +105,7 @@ tasks {
|
||||
}
|
||||
|
||||
nexusPublishing {
|
||||
repositories {
|
||||
this.repositories {
|
||||
sonatype {
|
||||
nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/"))
|
||||
snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
|
||||
|
@ -22,9 +22,9 @@ val properties = Properties().also { props ->
|
||||
|
||||
dependencies {
|
||||
implementation(gradleApi())
|
||||
implementation("org.ajoberstar.grgit:grgit-gradle:5.0.0")
|
||||
implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2")
|
||||
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.3")
|
||||
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.0")
|
||||
implementation("com.github.johnrengelman:shadow:8.1.1")
|
||||
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.5")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
@ -15,7 +15,6 @@ fun Project.applyPaperweightAdapterConfiguration() {
|
||||
|
||||
dependencies {
|
||||
"implementation"(project(":worldedit-bukkit"))
|
||||
"implementation"(platform("com.intellectualsites.bom:bom-1.18.x:1.9"))
|
||||
}
|
||||
|
||||
tasks.named("assemble") {
|
||||
|
@ -40,12 +40,11 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
||||
|
||||
dependencies {
|
||||
"compileOnly"("com.google.code.findbugs:jsr305:3.0.2")
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.9.2")
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.9.2")
|
||||
"testImplementation"("org.mockito:mockito-core:5.1.1")
|
||||
"testImplementation"("org.mockito:mockito-junit-jupiter:5.1.1")
|
||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.9.2")
|
||||
"implementation"(platform("com.intellectualsites.bom:bom-1.18.x:1.9"))
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.10.0")
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.10.0")
|
||||
"testImplementation"("org.mockito:mockito-core:5.4.0")
|
||||
"testImplementation"("org.mockito:mockito-junit-jupiter:5.4.0")
|
||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
}
|
||||
|
||||
// Java 8 turns on doclint which we fail
|
||||
@ -64,7 +63,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
||||
"https://www.antlr.org/api/Java/",
|
||||
"https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/",
|
||||
"https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/",
|
||||
"https://jd.papermc.io/paper/1.19/",
|
||||
"https://jd.papermc.io/paper/1.20/",
|
||||
"https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/"
|
||||
)
|
||||
docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}"
|
||||
|
@ -204,7 +204,7 @@ fun Project.applyLibrariesConfiguration() {
|
||||
from(libsComponent)
|
||||
|
||||
group = "com.fastasyncworldedit"
|
||||
artifactId = "FastAsyncWorldEdit-Libs-${project.name.capitalize()}"
|
||||
artifactId = "FastAsyncWorldEdit-Libs-${project.name.replaceFirstChar(Char::titlecase)}"
|
||||
version = version
|
||||
|
||||
pom {
|
||||
|
@ -1,51 +1,66 @@
|
||||
[versions]
|
||||
# Minecraft expectations
|
||||
paper = "1.20.1-R0.1-SNAPSHOT"
|
||||
fastutil = "8.5.9"
|
||||
guava = "31.1-jre"
|
||||
log4j = "2.19.0"
|
||||
gson = "2.10"
|
||||
snakeyaml = "2.0"
|
||||
|
||||
# Plugins
|
||||
dummypermscompat = "1.10"
|
||||
worldguard-bukkit = "7.0.7"
|
||||
worldguard-bukkit = "7.0.9"
|
||||
mapmanager = "1.8.0-SNAPSHOT"
|
||||
griefprevention = "16.18.1"
|
||||
griefdefender = "2.1.0-SNAPSHOT"
|
||||
residence = "4.5._13.1"
|
||||
towny = "0.98.4.18"
|
||||
towny = "0.99.5.10"
|
||||
plotsquared = "7.0.0-rc.4"
|
||||
|
||||
# Third party
|
||||
bstats = "3.0.2"
|
||||
sparsebitset = "1.2"
|
||||
parallelgzip = "1.0.5"
|
||||
adventure = "4.9.3"
|
||||
adventure = "4.14.0"
|
||||
adventure-bukkit = "4.3.0"
|
||||
checkerqual = "3.37.0"
|
||||
truezip = "6.8.4"
|
||||
auto-value = "1.10.1"
|
||||
auto-value = "1.10.2"
|
||||
findbugs = "3.0.2"
|
||||
rhino-runtime = "1.7.14"
|
||||
zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs
|
||||
antlr4 = "4.12.0"
|
||||
antlr4 = "4.13.0"
|
||||
json-simple = "1.1.1"
|
||||
jlibnoise = "1.0.0"
|
||||
jchronic = "0.2.4a"
|
||||
lz4-java = "1.8.0"
|
||||
lz4-stream = "1.0.0"
|
||||
commons-cli = "1.5.0"
|
||||
paperlib = "1.0.8"
|
||||
paster = "1.1.5"
|
||||
vault = "1.7.1"
|
||||
serverlib = "2.3.1"
|
||||
## Internal
|
||||
adventure-text-minimessage = "4.2.0-SNAPSHOT"
|
||||
text-adapter = "3.0.6"
|
||||
text = "3.0.4"
|
||||
piston = "0.5.7"
|
||||
|
||||
# Tests
|
||||
mockito = "5.2.0"
|
||||
mockito = "5.4.0"
|
||||
|
||||
# Gradle plugins
|
||||
pluginyml = "0.5.3"
|
||||
pluginyml = "0.6.0"
|
||||
minotaur = "2.8.3"
|
||||
|
||||
[libraries]
|
||||
# Minecraft expectations
|
||||
paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
|
||||
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
|
||||
log4jBom = { group = "org.apache.logging.log4j", name = "log4j-bom", version.ref = "log4j" }
|
||||
log4jApi = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml" }
|
||||
|
||||
# Plugins
|
||||
dummypermscompat = { group = "com.sk89q", name = "dummypermscompat", version.ref = "dummypermscompat" }
|
||||
@ -54,10 +69,13 @@ mapmanager = { group = "com.github.InventivetalentDev", name = "MapManager", ver
|
||||
griefprevention = { group = "com.github.TechFortress", name = "GriefPrevention", version.ref = "griefprevention" }
|
||||
griefdefender = { group = "com.griefdefender", name = "api", version.ref = "griefdefender" }
|
||||
residence = { group = "com.bekvon.bukkit.residence", name = "Residence", version.ref = "residence" }
|
||||
towny = { group = "com.github.TownyAdvanced", name = "Towny", version.ref = "towny" }
|
||||
towny = { group = "com.palmergames.bukkit.towny", name = "towny", version.ref = "towny" }
|
||||
plotSquaredCore = { group = "com.intellectualsites.plotsquared", name = "plotsquared-core", version.ref = "plotsquared" }
|
||||
plotSquaredBukkit = { group = "com.intellectualsites.plotsquared", name = "plotsquared-bukkit", version.ref = "plotsquared" }
|
||||
|
||||
# Third Party
|
||||
bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" }
|
||||
bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
|
||||
sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" }
|
||||
parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" }
|
||||
adventureNbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" }
|
||||
@ -74,6 +92,15 @@ jlibnoise = { group = "com.sk89q.lib", name = "jlibnoise", version.ref = "jlibno
|
||||
jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" }
|
||||
lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" }
|
||||
lz4JavaStream = { group = "net.jpountz", name = "lz4-java-stream", version.ref = "lz4-stream" }
|
||||
commonsCli = { group = "commons-cli", name = "commons-cli", version.ref = "commons-cli" }
|
||||
paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" }
|
||||
adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
|
||||
adventureMiniMessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventure" }
|
||||
adventureBukkit = { group = "net.kyori", name = "adventure-platform-bukkit", version.ref = "adventure-bukkit" }
|
||||
paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref = "paster" }
|
||||
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
|
||||
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
|
||||
checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" }
|
||||
|
||||
# Internal
|
||||
## Text
|
||||
@ -95,3 +122,4 @@ log4jCore = { group = "org.apache.logging.log4j", name = "log4j-core", version.r
|
||||
|
||||
[plugins]
|
||||
pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
|
||||
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binäre Datei nicht angezeigt.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
16
gradlew
vendored
16
gradlew
vendored
@ -85,9 +85,6 @@ done
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# 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"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
@ -133,10 +130,13 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
|
@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit"
|
||||
|
||||
include("worldedit-libs")
|
||||
|
||||
listOf("legacy", "1_17_1", "1_18_2", "1_19", "1_19_3","1_19_4").forEach {
|
||||
listOf("legacy", "1_17_1", "1_18_2", "1_19_4", "1_20").forEach {
|
||||
include("worldedit-bukkit:adapters:adapter-$it")
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
|
||||
|
||||
applyPaperweightAdapterConfiguration()
|
||||
|
||||
plugins {
|
||||
@ -19,6 +21,6 @@ configurations.all {
|
||||
|
||||
|
||||
dependencies {
|
||||
paperDevBundle("1.17.1-R0.1-20220414.034903-210")
|
||||
compileOnly("io.papermc:paperlib")
|
||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.17.1-R0.1-20220414.034903-210")
|
||||
compileOnly(libs.paperlib)
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
@ -658,10 +659,17 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
.registryAccess()
|
||||
.ownedRegistryOrThrow(
|
||||
Registry.BIOME_REGISTRY);
|
||||
return biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey)
|
||||
.map(CraftNamespacedKey::fromMinecraft)
|
||||
.collect(Collectors.toList());
|
||||
List<ResourceLocation> keys = biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
|
||||
List<NamespacedKey> namespacedKeys = new ArrayList<>();
|
||||
for (ResourceLocation key : keys) {
|
||||
try {
|
||||
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error converting biome key {}", key.toString(), e);
|
||||
}
|
||||
}
|
||||
return namespacedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -415,7 +415,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
BlockEntity tile = entry.getValue();
|
||||
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
||||
if (beacons == null) {
|
||||
@ -445,10 +445,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
// Changes may still be written to chunk SET
|
||||
// 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.
|
||||
char[] tmp = set.load(layerNo);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
char[] setArr = new char[tmp.length];
|
||||
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
||||
|
||||
// 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.
|
||||
|
@ -12,6 +12,7 @@ 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;
|
||||
@ -29,7 +30,9 @@ 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;
|
||||
@ -46,6 +49,8 @@ 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;
|
||||
|
||||
@ -59,6 +64,8 @@ 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;
|
||||
|
||||
@ -89,6 +96,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldRemove;
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldBits = PalettedContainer.class.getDeclaredField(Refraction.pickName("bits", "l"));
|
||||
@ -209,10 +218,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
} 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.
|
||||
@ -221,7 +232,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
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();
|
||||
@ -230,6 +255,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
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 {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
@ -10,6 +12,6 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
// https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
|
||||
paperDevBundle("1.18.2-R0.1-20220920.010157-167")
|
||||
compileOnly("io.papermc:paperlib")
|
||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.18.2-R0.1-20220920.010157-167")
|
||||
compileOnly(libs.paperlib)
|
||||
}
|
||||
|
@ -656,10 +656,17 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
.registryAccess()
|
||||
.ownedRegistryOrThrow(
|
||||
Registry.BIOME_REGISTRY);
|
||||
return biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull)
|
||||
.map(CraftNamespacedKey::fromMinecraft)
|
||||
.collect(Collectors.toList());
|
||||
List<ResourceLocation> keys = biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
|
||||
List<NamespacedKey> namespacedKeys = new ArrayList<>();
|
||||
for (ResourceLocation key : keys) {
|
||||
try {
|
||||
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error converting biome key {}", key.toString(), e);
|
||||
}
|
||||
}
|
||||
return namespacedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -408,7 +408,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
BlockEntity tile = entry.getValue();
|
||||
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
||||
if (beacons == null) {
|
||||
@ -491,9 +491,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
bitMask |= 1 << getSectionIndex;
|
||||
|
||||
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
|
||||
// this chunk GET when #updateGet is called. Future dords, please listen this time.
|
||||
char[] tmp = set.load(layerNo);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
char[] setArr = new char[tmp.length];
|
||||
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
||||
|
||||
// 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.
|
||||
|
@ -13,25 +13,26 @@ 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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
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.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.util.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;
|
||||
@ -39,7 +40,6 @@ 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.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.GlobalPalette;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
@ -49,8 +49,8 @@ import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||
import net.minecraft.world.level.gameevent.GameEventDispatcher;
|
||||
import net.minecraft.world.level.gameevent.GameEventListener;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_18_R2.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
@ -73,6 +73,8 @@ 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;
|
||||
|
||||
public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@ -104,6 +106,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldRemove;
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
|
||||
@ -237,10 +241,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
} 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.
|
||||
@ -249,7 +255,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
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();
|
||||
@ -258,6 +278,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
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 {
|
||||
|
@ -1,14 +0,0 @@
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
applyPaperweightAdapterConfiguration()
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
paperDevBundle("1.19.2-R0.1-20221206.184705-189")
|
||||
compileOnly("io.papermc:paperlib")
|
||||
}
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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_19_R1;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.network.chat.ChatType;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ServerboundClientInformationPacket;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.stats.Stat;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
class PaperweightFakePlayer extends ServerPlayer {
|
||||
|
||||
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(
|
||||
UUID.nameUUIDFromBytes("worldedit".getBytes()),
|
||||
"[WorldEdit]"
|
||||
);
|
||||
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
|
||||
|
||||
PaperweightFakePlayer(ServerLevel world) {
|
||||
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 position() {
|
||||
return ORIGIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die(DamageSource damagesource) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt openMenu(MenuProvider factory) {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOptions(ServerboundClientInformationPacket packet) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayClientMessage(Component message, boolean actionBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void awardStat(Stat<?> stat, int amount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void awardStat(Stat<?> stat) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvulnerableTo(DamageSource damageSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openTextEdit(SignBlockEntity sign) {
|
||||
}
|
||||
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* 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_19_R1;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PaperweightWorldNativeAccess implements
|
||||
WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
|
||||
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final PaperweightAdapter adapter;
|
||||
private final WeakReference<ServerLevel> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
|
||||
public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference<ServerLevel> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
private ServerLevel getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelChunk getChunk(int x, int z) {
|
||||
return getWorld().getChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
|
||||
int stateId = BlockStateIdAccess.getBlockStateId(state);
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.stateById(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) {
|
||||
return chunk.getBlockState(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState setBlockState(
|
||||
LevelChunk chunk,
|
||||
BlockPos position,
|
||||
net.minecraft.world.level.block.state.BlockState state
|
||||
) {
|
||||
return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(
|
||||
net.minecraft.world.level.block.state.BlockState block,
|
||||
BlockPos position
|
||||
) {
|
||||
return Block.updateFromNeighbourShapes(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getPosition(int x, int y, int z) {
|
||||
return new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPos position) {
|
||||
getWorld().getChunkSource().getLightEngine().checkBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(
|
||||
LevelChunk chunk,
|
||||
BlockPos position,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
|
||||
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(LevelChunk chunk) {
|
||||
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(LevelChunk chunk, BlockPos position) {
|
||||
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
|
||||
getWorld().getChunkSource().blockChanged(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(
|
||||
BlockPos pos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
ServerLevel world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.updateNeighborsAt(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
Block block = oldState.getBlock();
|
||||
fireNeighborChanged(pos, world, block, pos.west());
|
||||
fireNeighborChanged(pos, world, block, pos.east());
|
||||
fireNeighborChanged(pos, world, block, pos.below());
|
||||
fireNeighborChanged(pos, world, block, pos.above());
|
||||
fireNeighborChanged(pos, world, block, pos.north());
|
||||
fireNeighborChanged(pos, world, block, pos.south());
|
||||
}
|
||||
if (newState.hasAnalogOutputSignal()) {
|
||||
world.updateNeighbourForOutputSignal(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
|
||||
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(
|
||||
BlockPos pos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState,
|
||||
int recursionLimit
|
||||
) {
|
||||
ServerLevel world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(
|
||||
craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()),
|
||||
CraftBlockData.fromData(newState)
|
||||
);
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
|
||||
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(
|
||||
BlockPos pos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
getWorld().onBlockStateChange(pos, oldState, newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
|
||||
|
||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
private final Block block;
|
||||
private final BlockState blockState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
private final int opacity;
|
||||
private final CompoundTag tile;
|
||||
|
||||
public PaperweightBlockMaterial(Block block) {
|
||||
this(block, block.defaultBlockState());
|
||||
}
|
||||
|
||||
public PaperweightBlockMaterial(Block block, BlockState blockState) {
|
||||
this.block = block;
|
||||
this.blockState = blockState;
|
||||
this.material = blockState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(blockState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName(
|
||||
"properties", "aO"));
|
||||
this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo,
|
||||
Refraction.pickName("canOcclude", "n")
|
||||
);
|
||||
opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
||||
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
|
||||
BlockPos.ZERO,
|
||||
blockState
|
||||
);
|
||||
tile = tileEntity == null
|
||||
? null
|
||||
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public BlockState getState() {
|
||||
return blockState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return blockState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.isSolidBlocking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return blockState.isSignalSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().destroySpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getExplosionResistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFriction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return blockState.getLightEmission();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == PushReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == PushReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isRandomlyTicking(blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isFlammable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
// Removed in 1.16.1, this is not present in higher versions
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof EntityBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block instanceof EntityBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
// rgb field
|
||||
return material.getColor().col;
|
||||
}
|
||||
|
||||
}
|
@ -1,694 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R1.PaperweightAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.regen.PaperweightRegen;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.BooleanProperty;
|
||||
import com.sk89q.worldedit.registry.state.DirectionalProperty;
|
||||
import com.sk89q.worldedit.registry.state.EnumProperty;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.WritableRegistry;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlockState;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
|
||||
|
||||
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 char[] ibdToStateOrdinal = null;
|
||||
private int[] ordinalToIbdID = null;
|
||||
private boolean initialised = false;
|
||||
private Map<String, List<Property<?>>> allBlockProperties = null;
|
||||
|
||||
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new PaperweightAdapter();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
||||
return resourceLocation == null ? null : resourceLocation.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) {
|
||||
entity.save(compoundTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<net.minecraft.nbt.Tag> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState blockState = BlockTypesCache.states[i];
|
||||
PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial();
|
||||
int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState());
|
||||
char ordinal = blockState.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
Map<String, List<Property<?>>> properties = new HashMap<>();
|
||||
try {
|
||||
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
|
||||
Object obj = field.get(null);
|
||||
if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property<?> state)) {
|
||||
continue;
|
||||
}
|
||||
Property<?> property;
|
||||
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
|
||||
property = new BooleanProperty(
|
||||
state.getName(),
|
||||
(List<Boolean>) ImmutableList.copyOf(state.getPossibleValues())
|
||||
);
|
||||
} else if (state instanceof DirectionProperty) {
|
||||
property = new DirectionalProperty(
|
||||
state.getName(),
|
||||
state
|
||||
.getPossibleValues()
|
||||
.stream()
|
||||
.map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
|
||||
property = new EnumProperty(
|
||||
state.getName(),
|
||||
state
|
||||
.getPossibleValues()
|
||||
.stream()
|
||||
.map(e -> ((StringRepresentable) e).getSerializedName())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
|
||||
property = new IntegerProperty(
|
||||
state.getName(),
|
||||
(List<Integer>) ImmutableList.copyOf(state.getPossibleValues())
|
||||
);
|
||||
} else {
|
||||
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state
|
||||
.getClass()
|
||||
.getSimpleName());
|
||||
}
|
||||
properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> {
|
||||
if (v == null) {
|
||||
v = new ArrayList<>(Collections.singletonList(property));
|
||||
} else {
|
||||
v.add(property);
|
||||
}
|
||||
return v;
|
||||
});
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
allBlockProperties = ImmutableMap.copyOf(properties);
|
||||
}
|
||||
initialised = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new PaperweightBlockMaterial(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new PaperweightBlockMaterial(blockState.getBlock(), blockState);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public BlockState getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
final ServerLevel handle = craftWorld.getHandle();
|
||||
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
|
||||
final BlockPos blockPos = new BlockPos(x, y, z);
|
||||
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
|
||||
BlockState state = adapt(blockData);
|
||||
if (state == null) {
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(final Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final ServerLevel handle = craftWorld.getHandle();
|
||||
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
|
||||
final BlockPos blockPos = new BlockPos(x, y, z);
|
||||
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
|
||||
BlockState state = adapt(blockData);
|
||||
if (state == null) {
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
}
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||
if (blockEntity != null) {
|
||||
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
|
||||
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
LevelChunk levelChunk = craftChunk.getHandle();
|
||||
Level level = levelChunk.getLevel();
|
||||
|
||||
BlockPos blockPos = new BlockPos(x, y, z);
|
||||
net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState();
|
||||
LevelChunkSection[] levelChunkSections = levelChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
LevelChunkSection section = levelChunkSections[y4];
|
||||
|
||||
net.minecraft.world.level.block.state.BlockState existing;
|
||||
if (section == null) {
|
||||
existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getBlockState(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
|
||||
if (compoundTag != null || existing instanceof TileEntityBlock) {
|
||||
level.setBlock(blockPos, blockState, 0);
|
||||
// remove tile
|
||||
if (compoundTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
BlockEntity blockEntity = level.getBlockEntity(blockPos);
|
||||
if (blockEntity != null) {
|
||||
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
|
||||
tag.put("x", IntTag.valueOf(x));
|
||||
tag.put("y", IntTag.valueOf(y));
|
||||
tag.put("z", IntTag.valueOf(z));
|
||||
blockEntity.load(tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockState) {
|
||||
return true;
|
||||
}
|
||||
levelChunk.setBlockState(blockPos, blockState, false);
|
||||
}
|
||||
if (update) {
|
||||
level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new PaperweightFaweWorldNativeAccess(
|
||||
this,
|
||||
new WeakReference<>(((CraftWorld) world).getHandle())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundBinaryTag> saveTag = () -> {
|
||||
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
|
||||
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag);
|
||||
tags.put("Id", StringBinaryTag.of(id));
|
||||
return CompoundBinaryTag.from(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
|
||||
net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
net.minecraft.world.level.block.state.BlockState ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
|
||||
return BlockTypesCache.states[adaptToChar(blockState)];
|
||||
}
|
||||
|
||||
public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) {
|
||||
int id = Block.BLOCK_STATE_REGISTRY.getId(blockState);
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal[id];
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal[id];
|
||||
}
|
||||
try {
|
||||
init();
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
|
||||
);
|
||||
return BlockTypesCache.ReservedIDs.AIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char ibdIDToOrdinal(int id) {
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal[id];
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal[id];
|
||||
}
|
||||
init();
|
||||
return ibdToStateOrdinal[id];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getIbdToStateOrdinal() {
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return ibdToStateOrdinal;
|
||||
}
|
||||
init();
|
||||
return ibdToStateOrdinal;
|
||||
}
|
||||
}
|
||||
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
if (initialised) {
|
||||
return ordinalToIbdID[ordinal];
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return ordinalToIbdID[ordinal];
|
||||
}
|
||||
init();
|
||||
return ordinalToIbdID[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getOrdinalToIbdID() {
|
||||
if (initialised) {
|
||||
return ordinalToIbdID;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return ordinalToIbdID;
|
||||
}
|
||||
init();
|
||||
return ordinalToIbdID;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) {
|
||||
ServerLevel nmsWorld = ((CraftWorld) world).getHandle();
|
||||
ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
|
||||
if (map != null && wasAccessibleSinceLastSave(map)) {
|
||||
boolean flag = false;
|
||||
// PlayerChunk.d players = map.players;
|
||||
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
|
||||
*/ Stream.empty();
|
||||
|
||||
ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (chunkPacket) {
|
||||
ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = mapUtil.create(this, chunkPacket);
|
||||
chunkPacket.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.INSTANCE.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.connection.send(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.INSTANCE.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) {
|
||||
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
|
||||
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
|
||||
return blockState1.hasPostProcess(
|
||||
((CraftWorld) world).getHandle(),
|
||||
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
|
||||
ItemStack stack = new ItemStack(
|
||||
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())),
|
||||
baseItemStack.getAmount()
|
||||
);
|
||||
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(
|
||||
TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3,
|
||||
org.bukkit.World bukkitWorld
|
||||
) {
|
||||
TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType);
|
||||
if (bukkitType == TreeType.CHORUS_PLANT) {
|
||||
blockVector3 = blockVector3.add(
|
||||
0,
|
||||
1,
|
||||
0
|
||||
); // bukkit skips the feature gen which does this offset normally, so we have to add it back
|
||||
}
|
||||
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
|
||||
final BlockVector3 finalBlockVector = blockVector3;
|
||||
// Sync to main thread to ensure no clashes occur
|
||||
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
|
||||
serverLevel.captureTreeGeneration = true;
|
||||
serverLevel.captureBlockStates = true;
|
||||
try {
|
||||
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
|
||||
return null;
|
||||
}
|
||||
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
|
||||
} finally {
|
||||
serverLevel.captureBlockStates = false;
|
||||
serverLevel.captureTreeGeneration = false;
|
||||
serverLevel.capturedBlockStates.clear();
|
||||
}
|
||||
});
|
||||
if (placed == null || placed.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (CraftBlockState craftBlockState : placed.values()) {
|
||||
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(),
|
||||
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(net.minecraft.nbt.Tag foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.nbt.Tag fromNative(Tag foreign) {
|
||||
if (foreign instanceof PaperweightLazyCompoundTag) {
|
||||
return ((PaperweightLazyCompoundTag) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new PaperweightRegen(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new PaperweightGetBlocks(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biomeType) {
|
||||
final Registry<Biome> registry = MinecraftServer
|
||||
.getServer()
|
||||
.registryAccess()
|
||||
.ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
|
||||
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId());
|
||||
Biome biome = registry.get(resourceLocation);
|
||||
return registry.getId(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<NamespacedKey> getRegisteredBiomes() {
|
||||
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer())
|
||||
.getServer()
|
||||
.registryAccess()
|
||||
.ownedRegistryOrThrow(
|
||||
Registry.BIOME_REGISTRY);
|
||||
return biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull)
|
||||
.map(CraftNamespacedKey::fromMinecraft)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelighterFactory getRelighterFactory() {
|
||||
if (PaperLib.isPaper()) {
|
||||
return new PaperweightStarlightRelighterFactory();
|
||||
} else {
|
||||
return new NMSRelighterFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<Property<?>>> getAllProperties() {
|
||||
if (initialised) {
|
||||
return allBlockProperties;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (initialised) {
|
||||
return allBlockProperties;
|
||||
}
|
||||
init();
|
||||
return allBlockProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBatchProcessor getTickingPostProcessor() {
|
||||
return new PaperweightPostProcessor();
|
||||
}
|
||||
|
||||
private boolean wasAccessibleSinceLastSave(ChunkHolder holder) {
|
||||
if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) {
|
||||
try {
|
||||
return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder);
|
||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||
// fall-through
|
||||
}
|
||||
}
|
||||
// Papers new chunk system has no related replacement - therefor we assume true.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -1,248 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private final char[][] blocks;
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
final ServerLevel serverLevel;
|
||||
final LevelChunk levelChunk;
|
||||
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
||||
|
||||
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
|
||||
this.levelChunk = levelChunk;
|
||||
this.serverLevel = levelChunk.level;
|
||||
this.minHeight = serverLevel.getMinBuildHeight();
|
||||
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||
this.blocks = new char[getSectionCount()][];
|
||||
}
|
||||
|
||||
protected void storeTile(BlockEntity blockEntity) {
|
||||
tiles.put(
|
||||
BlockVector3.at(
|
||||
blockEntity.getBlockPos().getX(),
|
||||
blockEntity.getBlockPos().getY(),
|
||||
blockEntity.getBlockPos().getZ()
|
||||
),
|
||||
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<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) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
entities.add((CompoundTag) adapter.toNative(compoundTag));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
if (uuid.equals(tag.getUUID())) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return minHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionPosition() {
|
||||
return maxHeight >> 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionPosition() {
|
||||
return minHeight >> 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
||||
return PaperweightPlatformAdapter.adapt(biome, serverLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return serverLevel.getSectionsCount();
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
|
||||
if (biomes == null) {
|
||||
biomes = new PalettedContainer[getSectionCount()];
|
||||
}
|
||||
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomes[layer] = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.error(
|
||||
"Cannot correctly save biomes to history. Expected class type {} but got {}",
|
||||
PalettedContainer.class.getSimpleName(),
|
||||
biomeData.getClass().getSimpleName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
return state.toBaseBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
layer -= getMinSectionPosition();
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
layer -= getMinSectionPosition();
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] loadIfPresent(int layer) {
|
||||
layer -= getMinSectionPosition();
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
final int layer = (y >> 4) - getMinSectionPosition();
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_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", "a"));
|
||||
fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b"));
|
||||
fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b"));
|
||||
fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c"));
|
||||
fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c"));
|
||||
fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d"));
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientboundLevelChunkWithLightPacket createPacket() {
|
||||
// TODO ??? return new ClientboundLevelChunkPacket();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
@ -1,692 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
|
||||
import com.destroystokyo.paper.util.maplist.EntityList;
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.paper.world.ChunkEntitySlices;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IdMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.util.ExceptionCollector;
|
||||
import net.minecraft.util.SimpleBitStorage;
|
||||
import net.minecraft.util.ThreadingDetector;
|
||||
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.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.GlobalPalette;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import net.minecraft.world.level.gameevent.GameEventDispatcher;
|
||||
import net.minecraft.world.level.gameevent.GameEventListener;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.lang.reflect.Type;
|
||||
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.function.Function;
|
||||
|
||||
public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
public static final Field fieldData;
|
||||
|
||||
public static final Constructor<?> dataConstructor;
|
||||
|
||||
public static final Field fieldStorage;
|
||||
public static final Field fieldPalette;
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldThreadingDetector;
|
||||
private static final long fieldThreadingDetectorOffset;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
private static final MethodHandle methodRemoveGameEventListener;
|
||||
private static final MethodHandle methodremoveTickingBlockEntity;
|
||||
|
||||
private static final Field fieldRemove;
|
||||
|
||||
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 {
|
||||
try {
|
||||
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
|
||||
fieldData.setAccessible(true);
|
||||
|
||||
Class<?> dataClazz = fieldData.getType();
|
||||
dataConstructor = dataClazz.getDeclaredConstructors()[0];
|
||||
dataConstructor.setAccessible(true);
|
||||
|
||||
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
|
||||
fieldStorage.setAccessible(true);
|
||||
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
"b"
|
||||
), long.class);
|
||||
getVisibleChunkIfPresent.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
|
||||
|
||||
Unsafe unsafe = ReflectionUtils.getUnsafe();
|
||||
if (!PaperLib.isPaper()) {
|
||||
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
|
||||
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
|
||||
|
||||
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
} else {
|
||||
// in paper, the used methods are synchronized properly
|
||||
fieldThreadingDetector = null;
|
||||
fieldThreadingDetectorOffset = -1;
|
||||
|
||||
fieldLock = null;
|
||||
fieldLockOffset = -1;
|
||||
}
|
||||
|
||||
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
|
||||
Refraction.pickName("removeGameEventListener", "a"),
|
||||
BlockEntity.class,
|
||||
ServerLevel.class
|
||||
);
|
||||
removeGameEventListener.setAccessible(true);
|
||||
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
|
||||
|
||||
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
|
||||
Refraction.pickName(
|
||||
"removeBlockEntityTicker",
|
||||
"l"
|
||||
), BlockPos.class
|
||||
);
|
||||
removeBlockEntityTicker.setAccessible(true);
|
||||
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
|
||||
|
||||
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
|
||||
fieldRemove.setAccessible(true);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0) {
|
||||
throw new Error("data type scale not a power of two");
|
||||
}
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
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("entityManager");
|
||||
LEVEL_CHUNK_ENTITIES.setAccessible(true);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
POST_CHUNK_REWRITE = chunkRewrite;
|
||||
} 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();
|
||||
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(
|
||||
blocks,
|
||||
fieldThreadingDetectorOffset
|
||||
);
|
||||
synchronized (currentThreadingDetector) {
|
||||
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
|
||||
return delegateSemaphore;
|
||||
}
|
||||
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
|
||||
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||
if (!PaperLib.isPaper()) {
|
||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return serverLevel.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
} else {
|
||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
// Avoid "async" methods from the main thread.
|
||||
if (Fawe.isMainThread()) {
|
||||
return serverLevel.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
|
||||
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
|
||||
try {
|
||||
return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
|
||||
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (chunkHolder == null) {
|
||||
return;
|
||||
}
|
||||
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
|
||||
LevelChunk levelChunk;
|
||||
if (PaperLib.isPaper()) {
|
||||
// getChunkAtIfLoadedImmediately is paper only
|
||||
levelChunk = nmsWorld
|
||||
.getChunkSource()
|
||||
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
||||
} else {
|
||||
levelChunk = ((Optional<LevelChunk>) ((Either) chunkHolder
|
||||
.getTickingChunkFuture() // method is not present with new paper chunk system
|
||||
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left())
|
||||
.orElse(null);
|
||||
}
|
||||
if (levelChunk == null) {
|
||||
return;
|
||||
}
|
||||
TaskManager.taskManager().task(() -> {
|
||||
ClientboundLevelChunkWithLightPacket packet;
|
||||
if (PaperLib.isPaper()) {
|
||||
packet = new ClientboundLevelChunkWithLightPacket(
|
||||
levelChunk,
|
||||
nmsWorld.getChunkSource().getLightEngine(),
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
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,
|
||||
true
|
||||
);
|
||||
}
|
||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||
});
|
||||
}
|
||||
|
||||
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(layer, biomeRegistry, biomes);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int num_palette;
|
||||
if (get == null) {
|
||||
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null);
|
||||
} else {
|
||||
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null);
|
||||
}
|
||||
|
||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
|
||||
bitsPerEntry = 4;
|
||||
} else if (bitsPerEntry > 8) {
|
||||
bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1);
|
||||
}
|
||||
|
||||
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
|
||||
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
|
||||
final BitStorage nmsBits;
|
||||
if (bitsPerEntry == 0) {
|
||||
nmsBits = new ZeroBitStorage(4096);
|
||||
} else {
|
||||
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
|
||||
}
|
||||
List<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,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
||||
} catch (final Throwable e) {
|
||||
throw e;
|
||||
} finally {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
Arrays.fill(paletteToBlock, Integer.MAX_VALUE);
|
||||
Arrays.fill(blockStates, 0);
|
||||
Arrays.fill(blocksCopy, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||
private static LevelChunkSection newChunkSection(
|
||||
int layer,
|
||||
Registry<Biome> biomeRegistry,
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (biomes == null) {
|
||||
return new LevelChunkSection(layer, biomeRegistry);
|
||||
}
|
||||
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
|
||||
Block.BLOCK_STATE_REGISTRY,
|
||||
Blocks.AIR.defaultBlockState(),
|
||||
PalettedContainer.Strategy.SECTION_STATES,
|
||||
null
|
||||
);
|
||||
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
null
|
||||
);
|
||||
|
||||
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().ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
|
||||
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,175 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.registry.state.PropertyKey;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PaperweightPostProcessor implements IBatchProcessor {
|
||||
|
||||
@Override
|
||||
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||
return set;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
|
||||
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
|
||||
// The PostProcessor shouldn't be added, but just in case
|
||||
if (!tickFluid) {
|
||||
return;
|
||||
}
|
||||
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
|
||||
layer:
|
||||
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
|
||||
char[] set = iChunkSet.loadIfPresent(layer);
|
||||
if (set == null) {
|
||||
// No edit means no need to process
|
||||
continue;
|
||||
}
|
||||
char[] get = null;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char ordinal = set[i];
|
||||
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||
boolean fromGet = false; // Used for liquids
|
||||
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
if (get == null) {
|
||||
get = getBlocks.load(layer);
|
||||
}
|
||||
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
|
||||
// actually being set
|
||||
if (get == null) {
|
||||
continue layer;
|
||||
}
|
||||
fromGet = true;
|
||||
ordinal = replacedOrdinal = get[i];
|
||||
}
|
||||
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
continue;
|
||||
} else if (!fromGet) { // if fromGet, don't do the same again
|
||||
if (get == null) {
|
||||
get = getBlocks.load(layer);
|
||||
}
|
||||
replacedOrdinal = get[i];
|
||||
}
|
||||
boolean ticking = BlockTypesCache.ticking[ordinal];
|
||||
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
|
||||
boolean replacedWasLiquid = false;
|
||||
BlockState replacedState = null;
|
||||
if (!ticking) {
|
||||
// If the block being replaced was not ticking, it cannot be a liquid
|
||||
if (!replacedWasTicking) {
|
||||
continue;
|
||||
}
|
||||
// If the block being replaced is not fluid, we do not need to worry
|
||||
if (!(replacedWasLiquid =
|
||||
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
boolean liquid = state.getMaterial().isLiquid();
|
||||
int x = i & 15;
|
||||
int y = (i >> 8) & 15;
|
||||
int z = (i >> 4) & 15;
|
||||
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
|
||||
if (liquid || replacedWasLiquid) {
|
||||
if (liquid) {
|
||||
addFluid(getBlocks.serverLevel, state, position);
|
||||
continue;
|
||||
}
|
||||
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
|
||||
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
|
||||
// being ticked anyway. We only need it to be "hit" once.
|
||||
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
addFluid(getBlocks.serverLevel, replacedState, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Extent construct(final Extent child) {
|
||||
throw new UnsupportedOperationException("Processing only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessorScope getScope() {
|
||||
return ProcessorScope.READING_SET_BLOCKS;
|
||||
}
|
||||
|
||||
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||
if (set == null || get == null) {
|
||||
return false;
|
||||
}
|
||||
char ordinal;
|
||||
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||
if (x > 0 && set[i - 1] != reserved) {
|
||||
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (x < 15 && set[i + 1] != reserved) {
|
||||
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (z > 0 && set[i - 16] != reserved) {
|
||||
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (z < 15 && set[i + 16] != reserved) {
|
||||
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (y > 0 && set[i - 256] != reserved) {
|
||||
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (y < 15 && set[i + 256] != reserved) {
|
||||
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean isFluid(char ordinal) {
|
||||
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
|
||||
Fluid type;
|
||||
if (replacedState.getBlockType() == BlockTypes.LAVA) {
|
||||
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
|
||||
} else {
|
||||
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
|
||||
}
|
||||
serverLevel.scheduleTick(
|
||||
position,
|
||||
type,
|
||||
type.getTickDelay(serverLevel)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_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,161 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.LazyCompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import net.minecraft.nbt.NumericTag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PaperweightLazyCompoundTag extends LazyCompoundTag {
|
||||
|
||||
private final Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier;
|
||||
private CompoundTag compoundTag;
|
||||
|
||||
public PaperweightLazyCompoundTag(Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier) {
|
||||
super(new HashMap<>());
|
||||
this.compoundTagSupplier = compoundTagSupplier;
|
||||
}
|
||||
|
||||
public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) {
|
||||
this(() -> compoundTag);
|
||||
}
|
||||
|
||||
public net.minecraft.nbt.CompoundTag get() {
|
||||
return compoundTagSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Tag> getValue() {
|
||||
if (compoundTag == null) {
|
||||
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
|
||||
}
|
||||
return compoundTag.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundBinaryTag asBinaryTag() {
|
||||
getValue();
|
||||
return compoundTag.asBinaryTag();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return compoundTagSupplier.get().contains(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return compoundTagSupplier.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return compoundTagSupplier.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return compoundTagSupplier.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
|
||||
if (tag instanceof NumericTag numTag) {
|
||||
return numTag.getAsDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return compoundTagSupplier.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return compoundTagSupplier.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return compoundTagSupplier.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
|
||||
if (tag instanceof NumericTag numTag) {
|
||||
return numTag.getAsInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Tag> getList(String key) {
|
||||
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
|
||||
if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
for (net.minecraft.nbt.Tag elem : nbtList) {
|
||||
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
|
||||
list.add(new PaperweightLazyCompoundTag(compoundTag));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ListTag getListTag(String key) {
|
||||
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
|
||||
if (tag instanceof net.minecraft.nbt.ListTag) {
|
||||
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
|
||||
}
|
||||
return new ListTag(StringTag.class, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getLongArray(String key) {
|
||||
return compoundTagSupplier.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return compoundTagSupplier.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
|
||||
if (tag instanceof NumericTag numTag) {
|
||||
return numTag.getAsLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return compoundTagSupplier.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return compoundTagSupplier.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return compoundTagSupplier.get().toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,564 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_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_19_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.data.BuiltinRegistries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
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.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.StructureTemplateManager;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_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.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", "g"));
|
||||
generatorSettingBaseSupplierField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "f"));
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L"));
|
||||
chunkSourceField.setAccessible(true);
|
||||
|
||||
ringPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("ringPositions", "i"));
|
||||
ringPositionsField.setAccessible(true);
|
||||
|
||||
hasGeneratedPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("hasGeneratedPositions", "j"));
|
||||
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();
|
||||
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());
|
||||
|
||||
BiomeProvider biomeProvider = getBiomeProvider();
|
||||
|
||||
//init world
|
||||
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
|
||||
server,
|
||||
server.executor,
|
||||
session,
|
||||
newWorldData,
|
||||
originalServerWorld.dimension(),
|
||||
newOpts.dimensions().getOrThrow(levelStemResourceKey),
|
||||
new RegenNoOpWorldLoadListener(),
|
||||
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, 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(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,
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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(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,
|
||||
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,15 +0,0 @@
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
applyPaperweightAdapterConfiguration()
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
|
||||
paperDevBundle("1.19.3-R0.1-20230312.180621-141")
|
||||
compileOnly("io.papermc:paperlib")
|
||||
}
|
@ -1,286 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<LevelChunk,
|
||||
net.minecraft.world.level.block.state.BlockState, BlockPos> {
|
||||
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
private static final Direction[] NEIGHBOUR_ORDER = {
|
||||
Direction.EAST,
|
||||
Direction.WEST,
|
||||
Direction.DOWN,
|
||||
Direction.UP,
|
||||
Direction.NORTH,
|
||||
Direction.SOUTH
|
||||
};
|
||||
private final PaperweightFaweAdapter paperweightFaweAdapter;
|
||||
private final WeakReference<Level> level;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
private SideEffectSet sideEffectSet;
|
||||
|
||||
public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference<Level> level) {
|
||||
this.paperweightFaweAdapter = paperweightFaweAdapter;
|
||||
this.level = level;
|
||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
||||
}
|
||||
|
||||
private Level getLevel() {
|
||||
return Objects.requireNonNull(level.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelChunk getChunk(int x, int z) {
|
||||
return getLevel().getChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) {
|
||||
int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.stateById(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) {
|
||||
return levelChunk.getBlockState(blockPos);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized net.minecraft.world.level.block.state.BlockState setBlockState(
|
||||
LevelChunk levelChunk, BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState blockState
|
||||
) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return levelChunk.setBlockState(blockPos, blockState,
|
||||
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE)
|
||||
);
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
|
||||
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(
|
||||
net.minecraft.world.level.block.state.BlockState blockState,
|
||||
BlockPos blockPos
|
||||
) {
|
||||
return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getPosition(int x, int y, int z) {
|
||||
return new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPos blockPos) {
|
||||
getLevel().getChunkSource().getLightEngine().checkBlock(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
|
||||
if (blockEntity == null) {
|
||||
return false;
|
||||
}
|
||||
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag);
|
||||
blockEntity.load((CompoundTag) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(
|
||||
LevelChunk levelChunk, BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
|
||||
getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(LevelChunk levelChunk) {
|
||||
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) {
|
||||
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
|
||||
((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(
|
||||
BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
Level level = getLevel();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
level.blockUpdated(blockPos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (Direction direction : NEIGHBOUR_ORDER) {
|
||||
BlockPos shifted = blockPos.relative(direction);
|
||||
level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false);
|
||||
}
|
||||
}
|
||||
if (newState.hasAnalogOutputSignal()) {
|
||||
level.updateNeighbourForOutputSignal(blockPos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(
|
||||
BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState,
|
||||
int recursionLimit
|
||||
) {
|
||||
Level level = getLevel();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = level.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(
|
||||
craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()),
|
||||
CraftBlockData.fromData(newState)
|
||||
);
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit);
|
||||
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(
|
||||
BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState oldState,
|
||||
net.minecraft.world.level.block.state.BlockState newState
|
||||
) {
|
||||
getLevel().onBlockStateChange(blockPos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Set.copyOf(cachedChanges);
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Set.copyOf(cachedChunksToSend);
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> runnableVal = new RunnableVal<>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
|
||||
));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> runnableVal = new RunnableVal<>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
|
||||
));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
runnableVal.run();
|
||||
} else {
|
||||
TaskManager.taskManager().sync(runnableVal);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private record CachedChange(
|
||||
LevelChunk levelChunk,
|
||||
BlockPos blockPos,
|
||||
net.minecraft.world.level.block.state.BlockState blockState
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class PaperweightStarlightRelighterFactory implements RelighterFactory {
|
||||
|
||||
@Override
|
||||
public @Nonnull
|
||||
@SuppressWarnings("rawtypes")
|
||||
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
org.bukkit.World w = Bukkit.getWorld(world.getName());
|
||||
if (w == null) {
|
||||
return NullRelighter.INSTANCE;
|
||||
}
|
||||
return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue);
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
@ -9,6 +11,6 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
paperDevBundle("1.19.4-R0.1-20230331.112431-38")
|
||||
compileOnly("io.papermc:paperlib")
|
||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.19.4-R0.1-20230608.201059-104")
|
||||
compileOnly(libs.paperlib)
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
@ -50,7 +49,6 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
@ -60,7 +58,6 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.WritableRegistry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@ -71,14 +68,12 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -86,7 +81,6 @@ import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState;
|
||||
@ -306,54 +300,6 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
LevelChunk levelChunk = craftChunk.getHandle();
|
||||
Level level = levelChunk.getLevel();
|
||||
|
||||
BlockPos blockPos = new BlockPos(x, y, z);
|
||||
net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState();
|
||||
LevelChunkSection[] levelChunkSections = levelChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
LevelChunkSection section = levelChunkSections[y4];
|
||||
|
||||
net.minecraft.world.level.block.state.BlockState existing;
|
||||
if (section == null) {
|
||||
existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getBlockState(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
|
||||
if (compoundTag != null || existing instanceof TileEntityBlock) {
|
||||
level.setBlock(blockPos, blockState, 0);
|
||||
// remove tile
|
||||
if (compoundTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
BlockEntity blockEntity = level.getBlockEntity(blockPos);
|
||||
if (blockEntity != null) {
|
||||
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
|
||||
tag.put("x", IntTag.valueOf(x));
|
||||
tag.put("y", IntTag.valueOf(y));
|
||||
tag.put("z", IntTag.valueOf(z));
|
||||
blockEntity.load(tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockState) {
|
||||
return true;
|
||||
}
|
||||
levelChunk.setBlockState(blockPos, blockState, false);
|
||||
}
|
||||
if (update) {
|
||||
level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new PaperweightFaweWorldNativeAccess(
|
||||
@ -650,10 +596,17 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
.getServer()
|
||||
.registryAccess()
|
||||
.registryOrThrow(BIOME);
|
||||
return biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull)
|
||||
.map(CraftNamespacedKey::fromMinecraft)
|
||||
.collect(Collectors.toList());
|
||||
List<ResourceLocation> keys = biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
|
||||
List<NamespacedKey> namespacedKeys = new ArrayList<>();
|
||||
for (ResourceLocation key : keys) {
|
||||
try {
|
||||
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error converting biome key {}", key.toString(), e);
|
||||
}
|
||||
}
|
||||
return namespacedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +102,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
|
||||
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ()));
|
||||
cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
|
@ -332,6 +332,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
@ -408,7 +409,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
BlockEntity tile = entry.getValue();
|
||||
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
||||
if (beacons == null) {
|
||||
@ -490,9 +491,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
bitMask |= 1 << getSectionIndex;
|
||||
|
||||
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
|
||||
// this chunk GET when #updateGet is called. Future dords, please listen this time.
|
||||
char[] tmp = set.load(layerNo);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
char[] setArr = new char[tmp.length];
|
||||
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
||||
|
||||
// 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.
|
||||
|
@ -14,6 +14,7 @@ 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;
|
||||
@ -29,10 +30,12 @@ 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;
|
||||
@ -41,6 +44,7 @@ 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.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.GlobalPalette;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
@ -50,6 +54,8 @@ import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
@ -72,6 +78,8 @@ 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 net.minecraft.core.registries.Registries.BIOME;
|
||||
@ -105,12 +113,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldRemove;
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
static final boolean POST_CHUNK_REWRITE;
|
||||
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
|
||||
private static Field LEVEL_CHUNK_ENTITIES;
|
||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||
|
||||
static {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
try {
|
||||
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
|
||||
fieldData.setAccessible(true);
|
||||
@ -136,7 +147,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
"b"
|
||||
), long.class);
|
||||
getVisibleChunkIfPresent.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
|
||||
methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
|
||||
|
||||
Unsafe unsafe = ReflectionUtils.getUnsafe();
|
||||
if (!PaperLib.isPaper()) {
|
||||
@ -160,7 +171,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
ServerLevel.class
|
||||
);
|
||||
removeGameEventListener.setAccessible(true);
|
||||
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
|
||||
methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener);
|
||||
|
||||
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
|
||||
Refraction.pickName(
|
||||
@ -169,9 +180,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
), BlockPos.class
|
||||
);
|
||||
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", "q"));
|
||||
fieldRemove.setAccessible(true);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
|
||||
@ -197,16 +208,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
try {
|
||||
// Non-Paper
|
||||
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField("entityManager");
|
||||
LEVEL_CHUNK_ENTITIES.setAccessible(true);
|
||||
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "L"));
|
||||
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
POST_CHUNK_REWRITE = chunkRewrite;
|
||||
} catch (RuntimeException e) {
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,10 +277,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
} 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.
|
||||
@ -279,8 +291,23 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
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) chunk.getHandle(ChunkStatus.FULL);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -288,6 +315,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
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 {
|
||||
|
@ -60,6 +60,7 @@ 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;
|
||||
@ -440,7 +441,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
@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()));
|
||||
TaskManager.taskManager().task(() -> {
|
||||
final CraftWorld world = freshWorld.getWorld();
|
||||
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
|
||||
blockPopulator.populate(world, random, chunk);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
17
worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts
Normale Datei
17
worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts
Normale Datei
@ -0,0 +1,17 @@
|
||||
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
applyPaperweightAdapterConfiguration()
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
|
||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.1-R0.1-20230818.021330-113")
|
||||
compileOnly(libs.paperlib)
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
@ -27,21 +27,8 @@ import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.EndTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntArrayTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.LongArrayTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
@ -94,6 +81,7 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
|
||||
@ -137,13 +125,13 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
@ -194,8 +182,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
CraftServer.class.cast(Bukkit.getServer());
|
||||
|
||||
int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion();
|
||||
if (dataVersion != 3218) {
|
||||
throw new UnsupportedClassVersionError("Not 1.19.3!");
|
||||
if (dataVersion != 3463 && dataVersion != 3465) {
|
||||
throw new UnsupportedClassVersionError("Not 1.20(.1)!");
|
||||
}
|
||||
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
@ -363,10 +351,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
/*
|
||||
@Override
|
||||
public boolean hasCustomBiomeSupport() {
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>();
|
||||
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
|
||||
|
||||
/* @Override
|
||||
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.getId())))));
|
||||
chunk.setUnsaved(true);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new PaperweightWorldNativeAccess(this,
|
||||
return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this,
|
||||
new WeakReference<>(((CraftWorld) world).getHandle()));
|
||||
}
|
||||
|
||||
@ -548,6 +575,17 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
));
|
||||
}
|
||||
|
||||
/*@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
|
||||
public void sendFakeOP(Player player) {
|
||||
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
|
||||
@ -599,7 +637,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
final net.minecraft.core.Direction enumFacing = adapt(face);
|
||||
BlockHitResult rayTrace = new BlockHitResult(blockVec, enumFacing, blockPos, false);
|
||||
UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace);
|
||||
InteractionResult result = stack.useOn(context, InteractionHand.MAIN_HAND);
|
||||
InteractionResult result = stack.useOn(context);
|
||||
if (result != InteractionResult.SUCCESS) {
|
||||
if (worldServer.getBlockState(blockPos).use(worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) {
|
||||
result = InteractionResult.SUCCESS;
|
||||
@ -680,6 +718,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
seed,
|
||||
ImmutableList.of(),
|
||||
false,
|
||||
originalWorld.getRandomSequences(),
|
||||
env,
|
||||
gen,
|
||||
bukkitWorld.getBiomeProvider()
|
||||
@ -815,6 +854,17 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}*
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that is less likely to break
|
||||
// ------------------------------------------------------------------------
|
||||
@ -987,7 +1037,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
|
||||
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
|
||||
this.server = server;
|
||||
Field tickField = MinecraftServer.class.getDeclaredField(
|
||||
Refraction.pickName("nextTickTime", "ag")
|
||||
Refraction.pickName("nextTickTime", "ah")
|
||||
);
|
||||
if (tickField.getType() != long.class) {
|
||||
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/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
@ -29,12 +29,12 @@ import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.mojang.datafixers.DSL;
|
||||
import com.mojang.datafixers.DSL.TypeReference;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.datafixers.DataFixerBuilder;
|
||||
import com.mojang.datafixers.schemas.Schema;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
@ -221,7 +221,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataFixer buildOptimized(Executor executor) {
|
||||
public DataFixer buildOptimized(final Set<DSL.TypeReference> requiredTypes, Executor executor) {
|
||||
return buildUnoptimized();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@ -88,6 +88,6 @@ class PaperweightFakePlayer extends ServerPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openTextEdit(SignBlockEntity sign) {
|
||||
public void openTextEdit(SignBlockEntity sign, boolean front) {
|
||||
}
|
||||
}
|
@ -17,22 +17,22 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -101,7 +101,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) {
|
||||
public boolean updateTileEntity(BlockPos position, CompoundBinaryTag tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(LevelChunk chunk) {
|
||||
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
|
||||
return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -177,4 +177,5 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
|
||||
public void flush() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
|
||||
|
||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
private final Block block;
|
||||
private final BlockState blockState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
@ -35,13 +34,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
public PaperweightBlockMaterial(Block block, BlockState blockState) {
|
||||
this.block = block;
|
||||
this.blockState = blockState;
|
||||
this.material = blockState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(blockState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block,
|
||||
Refraction.pickName("properties", "aP"));
|
||||
Refraction.pickName("properties", "aN"));
|
||||
this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo,
|
||||
Refraction.pickName("canOcclude", "n")
|
||||
Refraction.pickName("canOcclude", "m")
|
||||
);
|
||||
opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
||||
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
|
||||
@ -65,10 +63,6 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return blockState.isAir();
|
||||
@ -81,7 +75,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.isSolidBlocking();
|
||||
return blockState.isOpaque();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -91,12 +85,14 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
// TODO: Better check ?
|
||||
return block instanceof LiquidBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isSolid();
|
||||
// TODO: Replace
|
||||
return blockState.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,12 +122,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == PushReaction.DESTROY;
|
||||
return blockState.getPistonPushReaction() == PushReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == PushReaction.BLOCK;
|
||||
return blockState.getPistonPushReaction() == PushReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,12 +137,12 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
return craftMaterial.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isFlammable();
|
||||
return craftMaterial.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -157,7 +153,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
return blockState.canBeReplaced();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -183,7 +179,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
// rgb field
|
||||
return material.getColor().col;
|
||||
return block.defaultMapColor().col;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
@ -17,13 +17,12 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2.PaperweightAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.regen.PaperweightRegen;
|
||||
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen.PaperweightRegen;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
@ -50,7 +49,6 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
@ -60,7 +58,6 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.WritableRegistry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@ -71,14 +68,12 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -86,15 +81,14 @@ import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlockState;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.util.CraftNamespacedKey;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -306,54 +300,6 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
LevelChunk levelChunk = craftChunk.getHandle();
|
||||
Level level = levelChunk.getLevel();
|
||||
|
||||
BlockPos blockPos = new BlockPos(x, y, z);
|
||||
net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState();
|
||||
LevelChunkSection[] levelChunkSections = levelChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
LevelChunkSection section = levelChunkSections[y4];
|
||||
|
||||
net.minecraft.world.level.block.state.BlockState existing;
|
||||
if (section == null) {
|
||||
existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getBlockState(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
|
||||
if (compoundTag != null || existing instanceof TileEntityBlock) {
|
||||
level.setBlock(blockPos, blockState, 0);
|
||||
// remove tile
|
||||
if (compoundTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
BlockEntity blockEntity = level.getBlockEntity(blockPos);
|
||||
if (blockEntity != null) {
|
||||
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
|
||||
tag.put("x", IntTag.valueOf(x));
|
||||
tag.put("y", IntTag.valueOf(y));
|
||||
tag.put("z", IntTag.valueOf(z));
|
||||
blockEntity.load(tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockState) {
|
||||
return true;
|
||||
}
|
||||
levelChunk.setBlockState(blockPos, blockState, false);
|
||||
}
|
||||
if (update) {
|
||||
level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new PaperweightFaweWorldNativeAccess(
|
||||
@ -650,10 +596,17 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
||||
.getServer()
|
||||
.registryAccess()
|
||||
.registryOrThrow(BIOME);
|
||||
return biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull)
|
||||
.map(CraftNamespacedKey::fromMinecraft)
|
||||
.collect(Collectors.toList());
|
||||
List<ResourceLocation> keys = biomeRegistry.stream()
|
||||
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
|
||||
List<NamespacedKey> namespacedKeys = new ArrayList<>();
|
||||
for (ResourceLocation key : keys) {
|
||||
try {
|
||||
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.error("Error converting biome key {}", key.toString(), e);
|
||||
}
|
||||
}
|
||||
return namespacedKeys;
|
||||
}
|
||||
|
||||
@Override
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
@ -17,12 +17,13 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -102,7 +103,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
|
||||
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ()));
|
||||
cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
@ -157,7 +158,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(LevelChunk levelChunk) {
|
||||
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
|
||||
return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
|
||||
}
|
||||
|
||||
@Override
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
|
||||
@ -20,7 +20,7 @@ import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -29,11 +29,7 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IdMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.*;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
@ -46,34 +42,17 @@ import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
@ -272,8 +251,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
|
||||
LightLayer.BLOCK,
|
||||
sectionPos,
|
||||
dataLayer,
|
||||
true
|
||||
dataLayer
|
||||
);
|
||||
}
|
||||
skyLight[alayer] = dataLayer;
|
||||
@ -300,7 +278,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
Arrays.fill(LAYER_COUNT, (byte) 15);
|
||||
dataLayer = new DataLayer(LAYER_COUNT);
|
||||
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos,
|
||||
dataLayer, true
|
||||
dataLayer
|
||||
);
|
||||
}
|
||||
blockLight[alayer] = dataLayer;
|
||||
@ -332,6 +310,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
@ -408,7 +387,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
BlockEntity tile = entry.getValue();
|
||||
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
||||
if (beacons == null) {
|
||||
@ -490,9 +469,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
bitMask |= 1 << getSectionIndex;
|
||||
|
||||
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
|
||||
// this chunk GET when #updateGet is called. Future dords, please listen this time.
|
||||
char[] tmp = set.load(layerNo);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
char[] setArr = new char[tmp.length];
|
||||
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
||||
|
||||
// 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.
|
||||
@ -526,8 +507,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||
null
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
@ -1049,8 +1029,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(
|
||||
lightLayer,
|
||||
sectionPos,
|
||||
dataLayer,
|
||||
true
|
||||
dataLayer
|
||||
);
|
||||
}
|
||||
synchronized (dataLayer) {
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
@ -8,7 +8,7 @@ import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.destroystokyo.paper.util.maplist.EntityList;
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
@ -14,6 +14,7 @@ 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;
|
||||
@ -29,10 +30,12 @@ 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;
|
||||
@ -41,6 +44,8 @@ import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.GlobalPalette;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
@ -50,13 +55,16 @@ import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftChunk;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -72,8 +80,11 @@ 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 {
|
||||
@ -103,14 +114,23 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
private static final MethodHandle methodRemoveGameEventListener;
|
||||
private static final MethodHandle methodremoveTickingBlockEntity;
|
||||
|
||||
/*
|
||||
* This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
* and is only needed to support 1.19.4 versions before *and* after this change.
|
||||
*/
|
||||
private static final MethodHandle CRAFT_CHUNK_GET_HANDLE;
|
||||
|
||||
private static final Field fieldRemove;
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
static final boolean POST_CHUNK_REWRITE;
|
||||
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
|
||||
private static Field LEVEL_CHUNK_ENTITIES;
|
||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||
|
||||
static {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
try {
|
||||
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
|
||||
fieldData.setAccessible(true);
|
||||
@ -124,11 +144,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
|
||||
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g"));
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
@ -136,7 +156,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
"b"
|
||||
), long.class);
|
||||
getVisibleChunkIfPresent.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
|
||||
methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
|
||||
|
||||
Unsafe unsafe = ReflectionUtils.getUnsafe();
|
||||
if (!PaperLib.isPaper()) {
|
||||
@ -160,7 +180,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
ServerLevel.class
|
||||
);
|
||||
removeGameEventListener.setAccessible(true);
|
||||
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
|
||||
methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener);
|
||||
|
||||
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
|
||||
Refraction.pickName(
|
||||
@ -169,9 +189,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
), BlockPos.class
|
||||
);
|
||||
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", "q"));
|
||||
fieldRemove.setAccessible(true);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
|
||||
@ -197,17 +217,30 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
try {
|
||||
// Non-Paper
|
||||
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField("entityManager");
|
||||
LEVEL_CHUNK_ENTITIES.setAccessible(true);
|
||||
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "M"));
|
||||
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
POST_CHUNK_REWRITE = chunkRewrite;
|
||||
} catch (RuntimeException e) {
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
} 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(
|
||||
@ -267,10 +300,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
} 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.
|
||||
@ -279,8 +314,23 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
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();
|
||||
}
|
||||
@ -288,6 +338,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
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 {
|
||||
@ -326,9 +383,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
levelChunk,
|
||||
nmsWorld.getChunkSource().getLightEngine(),
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false // last false is to not bother with x-ray
|
||||
null
|
||||
// last false is to not bother with x-ray
|
||||
);
|
||||
} else {
|
||||
// deprecated on paper - deprecation suppressed
|
||||
@ -336,8 +392,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
levelChunk,
|
||||
nmsWorld.getChunkSource().getLightEngine(),
|
||||
null,
|
||||
null,
|
||||
true
|
||||
null
|
||||
);
|
||||
}
|
||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||
@ -443,12 +498,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||
null
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
);
|
||||
}
|
||||
|
||||
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
||||
return new LevelChunkSection(blockStatePalettedContainer, biomes);
|
||||
} catch (final Throwable e) {
|
||||
throw e;
|
||||
} finally {
|
||||
@ -466,15 +520,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (biomes == null) {
|
||||
return new LevelChunkSection(layer, biomeRegistry);
|
||||
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,
|
||||
null
|
||||
PalettedContainer.Strategy.SECTION_STATES
|
||||
);
|
||||
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
|
||||
return new LevelChunkSection(dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -511,8 +564,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
|
||||
biomeRegistry,
|
||||
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||
null
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
);
|
||||
|
||||
final Palette<Holder<Biome>> biomePalette;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
|
||||
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;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
|
||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
|
||||
@ -8,7 +8,7 @@ import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.LazyCompoundTag;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.regen;
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.Regenerator;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
@ -11,7 +11,7 @@ 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_R2.PaperweightGetBlocks;
|
||||
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;
|
||||
@ -60,9 +60,10 @@ 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_19_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.generator.CustomChunkGenerator;
|
||||
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;
|
||||
|
||||
@ -110,17 +111,17 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
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(
|
||||
/*chunkStati.put(
|
||||
ChunkStatus.LIQUID_CARVERS,
|
||||
Concurrency.NONE
|
||||
); // liquid carvers: radius 0, but RADIUS and FULL change results
|
||||
); // 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
|
||||
// chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
@ -151,10 +152,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L"));
|
||||
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I"));
|
||||
chunkSourceField.setAccessible(true);
|
||||
|
||||
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w"));
|
||||
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "v"));
|
||||
generatorStructureStateField.setAccessible(true);
|
||||
|
||||
ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g"));
|
||||
@ -263,6 +264,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
seed,
|
||||
ImmutableList.of(),
|
||||
false,
|
||||
originalServerWorld.getRandomSequences(),
|
||||
environment,
|
||||
generator,
|
||||
biomeProvider
|
||||
@ -440,7 +442,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
@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()));
|
||||
TaskManager.taskManager().task(() -> {
|
||||
final CraftWorld world = freshWorld.getWorld();
|
||||
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
|
||||
blockPopulator.populate(world, random, chunk);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -545,7 +551,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.getName();
|
||||
return chunkStatus.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -557,8 +563,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
structureTemplateManager,
|
||||
threadedLevelLightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks,
|
||||
true
|
||||
accessibleChunks
|
||||
);
|
||||
}
|
||||
|
||||
@ -579,11 +584,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
||||
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);
|
@ -3,7 +3,7 @@ import io.papermc.paperweight.userdev.attribute.Obfuscation
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
id("com.modrinth.minotaur") version "2.+"
|
||||
alias(libs.plugins.minotaur)
|
||||
}
|
||||
|
||||
project.description = "Bukkit"
|
||||
@ -32,6 +32,10 @@ repositories {
|
||||
name = "OSS Sonatype Snapshots"
|
||||
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
maven {
|
||||
name = "Glaremasters"
|
||||
url = uri("https://repo.glaremasters.me/repository/towny/")
|
||||
}
|
||||
flatDir { dir(File("src/main/resources")) }
|
||||
}
|
||||
|
||||
@ -47,7 +51,13 @@ val adapters = configurations.create("adapters") {
|
||||
isCanBeResolved = true
|
||||
shouldResolveConsistentlyWith(configurations["runtimeClasspath"])
|
||||
attributes {
|
||||
attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, objects.named(Obfuscation.OBFUSCATED))
|
||||
attribute(Obfuscation.OBFUSCATION_ATTRIBUTE,
|
||||
if ((project.findProperty("enginehub.obf.none") as String?).toBoolean()) {
|
||||
objects.named(Obfuscation.NONE)
|
||||
} else {
|
||||
objects.named(Obfuscation.OBFUSCATED)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,19 +74,19 @@ dependencies {
|
||||
implementation(libs.fastutil)
|
||||
|
||||
// Platform expectations
|
||||
compileOnly("io.papermc.paper:paper-api") {
|
||||
compileOnly(libs.paper) {
|
||||
exclude("junit", "junit")
|
||||
exclude(group = "org.slf4j", module = "slf4j-api")
|
||||
}
|
||||
|
||||
// Logging
|
||||
localImplementation("org.apache.logging.log4j:log4j-api")
|
||||
localImplementation(libs.log4jApi)
|
||||
localImplementation(libs.log4jBom) {
|
||||
because("Spigot provides Log4J (sort of, not in API, implicitly part of server)")
|
||||
}
|
||||
|
||||
// Plugins
|
||||
compileOnly("com.github.MilkBowl:VaultAPI") { isTransitive = false }
|
||||
compileOnly(libs.vault) { isTransitive = false }
|
||||
compileOnly(libs.dummypermscompat) {
|
||||
exclude("com.github.MilkBowl", "VaultAPI")
|
||||
}
|
||||
@ -91,26 +101,26 @@ dependencies {
|
||||
compileOnly(libs.griefdefender) { isTransitive = false }
|
||||
compileOnly(libs.residence) { isTransitive = false }
|
||||
compileOnly(libs.towny) { isTransitive = false }
|
||||
compileOnly("com.plotsquared:PlotSquared-Bukkit") { isTransitive = false }
|
||||
compileOnly("com.plotsquared:PlotSquared-Core") { isTransitive = false }
|
||||
compileOnly(libs.plotSquaredBukkit) { isTransitive = false }
|
||||
compileOnly(libs.plotSquaredCore) { isTransitive = false }
|
||||
|
||||
// Third party
|
||||
implementation("io.papermc:paperlib")
|
||||
implementation("org.bstats:bstats-bukkit") { isTransitive = false }
|
||||
implementation(libs.paperlib)
|
||||
implementation(libs.bstatsBukkit) { isTransitive = false }
|
||||
implementation(libs.bstatsBase) { isTransitive = false }
|
||||
implementation("dev.notmyfault.serverlib:ServerLib")
|
||||
implementation("com.intellectualsites.paster:Paster") { isTransitive = false }
|
||||
implementation(libs.serverlib)
|
||||
implementation(libs.paster) { isTransitive = false }
|
||||
api(libs.lz4Java) { isTransitive = false }
|
||||
api(libs.sparsebitset) { isTransitive = false }
|
||||
api(libs.parallelgzip) { isTransitive = false }
|
||||
compileOnly("net.kyori:adventure-api")
|
||||
compileOnlyApi("org.checkerframework:checker-qual")
|
||||
compileOnly(libs.adventureApi)
|
||||
compileOnlyApi(libs.checkerqual)
|
||||
|
||||
// Tests
|
||||
testImplementation(libs.mockito)
|
||||
testImplementation("net.kyori:adventure-api")
|
||||
testImplementation("org.checkerframework:checker-qual")
|
||||
testImplementation("io.papermc.paper:paper-api") { isTransitive = true }
|
||||
testImplementation(libs.adventureApi)
|
||||
testImplementation(libs.checkerqual)
|
||||
testImplementation(libs.paper) { isTransitive = true }
|
||||
}
|
||||
|
||||
tasks.named<Copy>("processResources") {
|
||||
@ -173,7 +183,7 @@ tasks.named<ShadowJar>("shadowJar") {
|
||||
include(dependency("org.lz4:lz4-java:1.8.0"))
|
||||
}
|
||||
relocate("net.kyori", "com.fastasyncworldedit.core.adventure") {
|
||||
include(dependency("net.kyori:adventure-nbt:4.9.3"))
|
||||
include(dependency("net.kyori:adventure-nbt:4.14.0"))
|
||||
}
|
||||
relocate("com.zaxxer", "com.fastasyncworldedit.core.math") {
|
||||
include(dependency("com.zaxxer:SparseBitSet:1.2"))
|
||||
@ -196,7 +206,7 @@ tasks {
|
||||
versionNumber.set("${project.version}")
|
||||
versionType.set("release")
|
||||
uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar"))
|
||||
gameVersions.addAll(listOf("1.19.4", "1.19.3", "1.19.2", "1.19.1", "1.19", "1.18.2", "1.17.1", "1.16.5"))
|
||||
gameVersions.addAll(listOf("1.20.1", "1.20", "1.19.4", "1.18.2", "1.17.1", "1.16.5"))
|
||||
loaders.addAll(listOf("paper", "spigot"))
|
||||
changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" +
|
||||
"FastAsyncWorldEdit/releases/tag/${project.version}")
|
||||
|
@ -108,6 +108,14 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
if (version.isEqualOrHigherThan(MinecraftVersion.CAVES_18) && Settings.settings().HISTORY.SMALL_EDITS) {
|
||||
LOGGER.warn("Small-edits enabled (maximum y range of 0 -> 256) with 1.18 world heights. Are you sure?");
|
||||
}
|
||||
|
||||
if (version.isEqualOrLowerThan(MinecraftVersion.ONE_DOT_SIXTEEN_EOL)) {
|
||||
LOGGER.warn("You are running Minecraft 1.16.5. This version has been released over two years ago (January 2021).");
|
||||
LOGGER.warn("FastAsyncWorldEdit will stop operating on this version in the near future.");
|
||||
LOGGER.warn("Neither Mojang, nor Spigot or other software vendors support this version anymore." +
|
||||
"Please update your server to a newer version of Minecraft (1.20+) to continue receiving updates and " +
|
||||
"support.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,7 +233,7 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
final Plugin residencePlugin = Bukkit.getServer().getPluginManager().getPlugin("Residence");
|
||||
if (residencePlugin != null && residencePlugin.isEnabled()) {
|
||||
try {
|
||||
managers.add(new ResidenceFeature(residencePlugin, this));
|
||||
managers.add(new ResidenceFeature(residencePlugin));
|
||||
LOGGER.info("Attempting to use plugin 'Residence'");
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
@ -317,11 +325,11 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
if (plotSquared == null) {
|
||||
return;
|
||||
}
|
||||
if (PlotSquared.get().getVersion().version[0] == 6) {
|
||||
if (PlotSquared.get().getVersion().version[0] == 7) {
|
||||
WEManager.weManager().addManager(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' v6 found. Using it now.");
|
||||
LOGGER.info("Plugin 'PlotSquared' v7 found. Using it now.");
|
||||
} else {
|
||||
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
|
||||
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v7.");
|
||||
LOGGER.info("https://www.spigotmc.org/resources/77506/");
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ package com.fastasyncworldedit.bukkit.adapter;
|
||||
import co.aikar.timings.Timings;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener;
|
||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@ -31,7 +29,7 @@ public class BukkitQueueHandler extends QueueHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
public void startUnsafe(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = true;
|
||||
if (parallel) {
|
||||
try {
|
||||
@ -51,7 +49,7 @@ public class BukkitQueueHandler extends QueueHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
public void endUnsafe(boolean parallel) {
|
||||
ChunkListener.physicsFreeze = false;
|
||||
if (parallel) {
|
||||
try {
|
||||
|
@ -84,7 +84,7 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
||||
getArr = get.apply(layer);
|
||||
}
|
||||
// write to set array as this should be a copied array, and will be important when the changes are written
|
||||
// to the GET chunk cached by FAWE
|
||||
// to the GET chunk cached by FAWE. Future dords, actually read this comment please.
|
||||
set[i] = switch (ordinal = getArr[i]) {
|
||||
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
|
||||
nonAir--;
|
||||
|
@ -165,7 +165,11 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
||||
.setNameFormat("fawe-regen-%d")
|
||||
.build()
|
||||
);
|
||||
} // else using sequential chunk generation, concurrent not supported
|
||||
} else { // else using sequential chunk generation, concurrent not supported
|
||||
executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
|
||||
.setNameFormat("fawe-regen-%d")
|
||||
.build());
|
||||
}
|
||||
|
||||
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
||||
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
||||
@ -253,10 +257,13 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else { // Concurrency.NONE or generateConcurrent == false
|
||||
// run sequential
|
||||
for (long xz : coords) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
// run sequential but submit to different thread
|
||||
// running regen on the main thread otherwise triggers async-only events on the main thread
|
||||
executor.submit(() -> {
|
||||
for (long xz : coords) {
|
||||
chunkStatus.processChunkSave(xz, worldlimits.get(radius).get(xz));
|
||||
}
|
||||
}).get(); // wait until finished this step
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,48 +371,6 @@ public abstract class ChunkListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent firework from loading chunks.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
if (!Settings.settings().TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) {
|
||||
Chunk chunk = event.getChunk();
|
||||
Entity[] entities = chunk.getEntities();
|
||||
World world = chunk.getWorld();
|
||||
|
||||
Exception e = new Exception();
|
||||
int start = 14;
|
||||
int end = 22;
|
||||
int depth = Math.min(end, getDepth(e));
|
||||
|
||||
for (int frame = start; frame < depth; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
if (elem == null) {
|
||||
return;
|
||||
}
|
||||
String className = elem.getClassName();
|
||||
int len = className.length();
|
||||
if (len > 15 && className.charAt(len - 15) == 'E' && className
|
||||
.endsWith("EntityFireworks")) {
|
||||
for (Entity ent : world.getEntities()) {
|
||||
if (ent.getType() == EntityType.FIREWORK) {
|
||||
Vector velocity = ent.getVelocity();
|
||||
double vertical = Math.abs(velocity.getY());
|
||||
if (Math.abs(velocity.getX()) > vertical
|
||||
|| Math.abs(velocity.getZ()) > vertical) {
|
||||
LOGGER.warn(
|
||||
"[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at {}",
|
||||
ent.getLocation());
|
||||
ent.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onItemSpawn(ItemSpawnEvent event) {
|
||||
if (physicsFreeze) {
|
||||
|
@ -2,10 +2,7 @@ package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
|
@ -3,7 +3,6 @@ package com.fastasyncworldedit.bukkit.regions;
|
||||
import com.bekvon.bukkit.residence.Residence;
|
||||
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
|
||||
import com.bekvon.bukkit.residence.protection.CuboidArea;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
@ -19,13 +18,8 @@ public class ResidenceFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final FaweBukkit plugin;
|
||||
private final Plugin residence;
|
||||
|
||||
public ResidenceFeature(final Plugin residencePlugin, final FaweBukkit p3) {
|
||||
public ResidenceFeature(final Plugin residencePlugin) {
|
||||
super(residencePlugin.getName());
|
||||
this.residence = residencePlugin;
|
||||
this.plugin = p3;
|
||||
LOGGER.info("Plugin 'Residence' found. Using it now.");
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.palmergames.bukkit.towny.TownyUniverse;
|
||||
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
||||
import com.palmergames.bukkit.towny.object.PlayerCache;
|
||||
import com.palmergames.bukkit.towny.TownyAPI;
|
||||
import com.palmergames.bukkit.towny.object.Resident;
|
||||
import com.palmergames.bukkit.towny.object.Town;
|
||||
import com.palmergames.bukkit.towny.object.TownBlock;
|
||||
@ -14,7 +11,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -24,11 +20,8 @@ public class TownyFeature extends BukkitMaskManager implements Listener {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Plugin towny;
|
||||
|
||||
public TownyFeature(Plugin townyPlugin) {
|
||||
super(townyPlugin.getName());
|
||||
this.towny = townyPlugin;
|
||||
LOGGER.info("Plugin 'Towny' found. Using it now.");
|
||||
}
|
||||
|
||||
@ -36,31 +29,27 @@ public class TownyFeature extends BukkitMaskManager implements Listener {
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
Resident resident;
|
||||
try {
|
||||
resident = TownyUniverse.getInstance().getResident(player.getName());
|
||||
try {
|
||||
if (block.getResident().equals(resident)) {
|
||||
return true;
|
||||
}
|
||||
} catch (NotRegisteredException ignored) {
|
||||
}
|
||||
Town town = block.getTown();
|
||||
if (town.isMayor(resident)) {
|
||||
Resident resident = TownyAPI.getInstance().getResident(player);
|
||||
if (resident == null) {
|
||||
return false;
|
||||
}
|
||||
if (block.hasResident(resident) || block.hasTrustedResident(resident)) {
|
||||
return true;
|
||||
}
|
||||
Town town = block.getTownOrNull(); // Will not be null, because block is not null.
|
||||
if (town.isMayor(resident) || town.hasTrustedResident(resident)) {
|
||||
return true;
|
||||
}
|
||||
if (!town.hasResident(resident)) {
|
||||
return false;
|
||||
}
|
||||
if (player.hasPermission("fawe.towny.*")) {
|
||||
return true;
|
||||
}
|
||||
for (String rank : resident.getTownRanks()) {
|
||||
if (player.hasPermission("fawe.towny." + rank)) {
|
||||
return true;
|
||||
}
|
||||
if (!town.hasResident(resident)) {
|
||||
return false;
|
||||
}
|
||||
if (player.hasPermission("fawe.towny.*")) {
|
||||
return true;
|
||||
}
|
||||
for (String rank : resident.getTownRanks()) {
|
||||
if (player.hasPermission("fawe.towny." + rank)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (NotRegisteredException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -69,32 +58,23 @@ public class TownyFeature extends BukkitMaskManager implements Listener {
|
||||
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) {
|
||||
final Player player = BukkitAdapter.adapt(wePlayer);
|
||||
final Location location = player.getLocation();
|
||||
try {
|
||||
final PlayerCache cache = ((Towny) this.towny).getCache(player);
|
||||
final WorldCoord mycoord = cache.getLastTownBlock();
|
||||
if (mycoord == null) {
|
||||
return null;
|
||||
}
|
||||
final TownBlock myplot = mycoord.getTownBlock();
|
||||
if (myplot == null) {
|
||||
return null;
|
||||
}
|
||||
boolean isMember = isAllowed(player, myplot);
|
||||
if (isMember) {
|
||||
final Chunk chunk = location.getChunk();
|
||||
final BlockVector3 pos1 = BlockVector3
|
||||
.at(chunk.getX() * 16, 0, chunk.getZ() * 16);
|
||||
final BlockVector3 pos2 = BlockVector3.at(
|
||||
chunk.getX() * 16 + 15, 156, chunk.getZ() * 16
|
||||
+ 15);
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(BukkitAdapter.adapt(player), myplot);
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
final WorldCoord mycoord = WorldCoord.parseWorldCoord(location);
|
||||
if (mycoord.isWilderness()) {
|
||||
return null;
|
||||
}
|
||||
final TownBlock myplot = mycoord.getTownBlockOrNull(); // Will not be null, because of the isWilderness() test above.
|
||||
boolean isMember = isAllowed(player, myplot);
|
||||
if (isMember) {
|
||||
final Location loc1 = mycoord.getLowerMostCornerLocation();
|
||||
final Location loc2 = mycoord.getUpperMostCornerLocation();
|
||||
final BlockVector3 pos1 = BlockVector3.at(loc1.getX(), loc1.getY(), loc1.getZ());
|
||||
final BlockVector3 pos2 = BlockVector3.at(loc2.getX() - 1, loc2.getY(), loc2.getZ() - 1);
|
||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||
@Override
|
||||
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
|
||||
return isAllowed(BukkitAdapter.adapt(player), myplot);
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -171,18 +171,17 @@ public class FaweDelegateRegionManager {
|
||||
.limitUnlimited()
|
||||
.changeSetNull()
|
||||
.build();
|
||||
File schematicFile = new File(hybridPlotWorld.getRoot(), "plot.schem");
|
||||
File schematicFile = new File(hybridPlotWorld.getSchematicRoot(), "plot.schem");
|
||||
if (!schematicFile.exists()) {
|
||||
schematicFile = new File(hybridPlotWorld.getRoot(), "plot.schematic");
|
||||
schematicFile = new File(hybridPlotWorld.getSchematicRoot(), "plot.schematic");
|
||||
}
|
||||
BlockVector3 to = plot.getBottomAbs().getBlockVector3().withY(Settings.Schematics.PASTE_ON_TOP
|
||||
? hybridPlotWorld.SCHEM_Y
|
||||
: hybridPlotWorld.getMinBuildHeight());
|
||||
BlockVector3 to = plot.getBottomAbs().getBlockVector3().withY(hybridPlotWorld.getPlotYStart());
|
||||
try {
|
||||
Clipboard clip = ClipboardFormats
|
||||
.findByFile(schematicFile)
|
||||
.getReader(new FileInputStream(schematicFile))
|
||||
.read();
|
||||
clip.setOrigin(clip.getRegion().getMinimumPoint());
|
||||
clip.paste(scheditsession, to, true, true, true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -214,7 +213,7 @@ public class FaweDelegateRegionManager {
|
||||
) {
|
||||
TaskManager.taskManager().async(() -> {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
//todo because of the following code this should proably be in the Bukkit module
|
||||
//todo because of the following code this should probably be in the Bukkit module
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName()));
|
||||
EditSession sessionA = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World)
|
||||
|
@ -152,6 +152,7 @@ public class FaweDelegateSchematicHandler {
|
||||
final BlockVector3 to = BlockVector3
|
||||
.at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
|
||||
final Clipboard clipboard = schematic.getClipboard();
|
||||
clipboard.setOrigin(clipboard.getRegion().getMinimumPoint());
|
||||
clipboard.paste(editSession, to, true, false, true);
|
||||
if (whenDone != null) {
|
||||
whenDone.value = true;
|
||||
|
@ -1,13 +1,15 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.command.SubCommand;
|
||||
import com.plotsquared.core.configuration.caption.StaticCaption;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
|
||||
@ -33,7 +35,7 @@ public class FaweTrim extends SubCommand {
|
||||
return false;
|
||||
}
|
||||
if (!PlotSquared.platform().worldUtil().isWorld(strings[0])) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("errors.not_valid_plot_world"), Templates.of("value", strings[0]));
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("errors.not_valid_plot_world"), TagResolver.resolver("value", Tag.inserting(Component.text(strings[0]))));
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
|
@ -6,11 +6,9 @@ import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.Permissions;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.RunnableVal2;
|
||||
import com.plotsquared.core.util.task.RunnableVal3;
|
||||
@ -24,6 +22,9 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -56,7 +57,7 @@ public class PlotSetBiome extends Command {
|
||||
) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), TranslatableCaption.of("errors.not_in_plot"));
|
||||
checkTrue(
|
||||
plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.admin.command.generatebiome"),
|
||||
plot.isOwner(player.getUUID()) || player.hasPermission("plots.admin.command.generatebiome"),
|
||||
TranslatableCaption.of("permission.no_plot_perms")
|
||||
);
|
||||
if (plot.getRunning() != 0) {
|
||||
@ -64,7 +65,7 @@ public class PlotSetBiome extends Command {
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, TranslatableCaption.of("commandconfig.command_syntax"),
|
||||
Templates.of("value", getUsage())
|
||||
TagResolver.resolver("value", Tag.inserting(Component.text(getUsage())))
|
||||
);
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry =
|
||||
@ -80,7 +81,7 @@ public class PlotSetBiome extends Command {
|
||||
player.sendMessage(TranslatableCaption.of("biome.need_biome"));
|
||||
player.sendMessage(
|
||||
TranslatableCaption.of("commandconfig.subcommand_set_options_header"),
|
||||
Templates.of("values", biomes)
|
||||
TagResolver.resolver("value", Tag.inserting(Component.text(biomes)))
|
||||
);
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
@ -23,8 +23,11 @@ import com.sk89q.worldedit.world.World;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@ -39,7 +42,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
if (Settings.FAWE_Components.FAWE_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
|
||||
new FaweTrim();
|
||||
// new FaweTrim();
|
||||
}
|
||||
// TODO: revisit this later on
|
||||
/*
|
||||
@ -66,28 +69,32 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
* @param plot the {@link Plot}
|
||||
* @param type the {@link MaskType}
|
||||
* @return {@code true} if the player is the plot owner, trusted, has the permission fawe.plotsquared.member
|
||||
* or fawe.plotsquared.admin and the NoWorldeditFlag is not set; otherwise {@code false}
|
||||
* or fawe.plotsquared.admin and the NoWorldeditFlag is not set; otherwise {@code false}
|
||||
*/
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type) {
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type, boolean notify) {
|
||||
if (plot == null) {
|
||||
return false;
|
||||
}
|
||||
UUID uid = player.getUniqueId();
|
||||
if (plot.getFlag(NoWorldeditFlag.class)) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.noworldeditflag")
|
||||
));
|
||||
if (notify) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.noworldeditflag")
|
||||
));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (plot.isOwner(uid) || player.hasPermission("fawe.plotsquared.admin")) {
|
||||
return true;
|
||||
}
|
||||
if (type != MaskType.MEMBER) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.owner.only")
|
||||
));
|
||||
if (notify) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.owner.only")
|
||||
));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)) {
|
||||
@ -95,26 +102,32 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
}
|
||||
if (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) {
|
||||
if (!player.hasPermission("fawe.plotsquared.member")) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.error.no-perm", "fawe.plotsquared.member")
|
||||
));
|
||||
if (notify) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.error.no-perm", "fawe.plotsquared.member")
|
||||
));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!plot.getOwners().isEmpty() && plot.getOwners().stream().anyMatch(this::playerOnline)) {
|
||||
return true;
|
||||
} else {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.owner.offline")
|
||||
));
|
||||
if (notify) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.plot.owner.offline")
|
||||
));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.not.added")
|
||||
));
|
||||
if (notify) {
|
||||
player.print(Caption.of(
|
||||
"fawe.cancel.reason.no.region.reason",
|
||||
Caption.of("fawe.cancel.reason.no.region.not.added")
|
||||
));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -127,14 +140,19 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type, boolean isWhitelist) {
|
||||
public FaweMask getMask(final Player player, final MaskType type, final boolean isWhitelist) {
|
||||
return getMask(player, type, isWhitelist, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type, boolean isWhitelist, boolean notify) {
|
||||
final PlotPlayer<org.bukkit.entity.Player> pp = PlotPlayer.from(BukkitAdapter.adapt(player));
|
||||
if (pp == null) {
|
||||
return null;
|
||||
}
|
||||
final Set<CuboidRegion> regions;
|
||||
Plot plot = pp.getCurrentPlot();
|
||||
if (isAllowed(player, plot, type)) {
|
||||
if (isAllowed(player, plot, type, notify)) {
|
||||
regions = plot.getRegions();
|
||||
} else {
|
||||
plot = null;
|
||||
@ -176,15 +194,37 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
maskedRegion = new RegionIntersection(world, weRegions);
|
||||
}
|
||||
|
||||
return new FaweMask(maskedRegion) {
|
||||
@Override
|
||||
public boolean isValid(Player player, MaskType type) {
|
||||
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(finalPlot)) {
|
||||
return false;
|
||||
}
|
||||
return isAllowed(player, finalPlot, type);
|
||||
if (plot == null) {
|
||||
return new FaweMask(maskedRegion);
|
||||
}
|
||||
|
||||
return new PlotSquaredMask(maskedRegion, finalPlot);
|
||||
}
|
||||
|
||||
private final class PlotSquaredMask extends FaweMask {
|
||||
|
||||
private final Plot plot;
|
||||
private final WeakReference<Set<Plot>> connectedPlots;
|
||||
private final boolean singlePlot;
|
||||
|
||||
private PlotSquaredMask(@Nonnull Region region, @Nonnull Plot plot) {
|
||||
super(region);
|
||||
this.plot = Objects.requireNonNull(plot);
|
||||
Set<Plot> connected = plot.getConnectedPlots();
|
||||
connectedPlots = new WeakReference<>(connected);
|
||||
singlePlot = connected.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Player player, MaskType type, boolean notify) {
|
||||
if ((!connectedPlots.refersTo(plot.getConnectedPlots()) && (!singlePlot || plot
|
||||
.getConnectedPlots()
|
||||
.size() > 1)) || (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot))) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return isAllowed(player, plot, type, notify);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import java.util.regex.Pattern;
|
||||
public class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
|
||||
public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16);
|
||||
public static final MinecraftVersion ONE_DOT_SIXTEEN_EOL = new MinecraftVersion(1, 16, 5);
|
||||
public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17);
|
||||
public static final MinecraftVersion CAVES_18 = new MinecraftVersion(1, 18);
|
||||
private static MinecraftVersion current = null;
|
||||
|
@ -21,11 +21,8 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor;
|
||||
import com.sk89q.worldedit.extension.platform.Locatable;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extension.platform.AbstractCommandBlockActor;
|
||||
import com.sk89q.worldedit.session.SessionKey;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.auth.AuthorizationException;
|
||||
import com.sk89q.worldedit.util.formatting.WorldEditText;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
@ -43,22 +40,20 @@ import java.util.UUID;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements Locatable {
|
||||
public class BukkitBlockCommandSender extends AbstractCommandBlockActor {
|
||||
|
||||
private static final String UUID_PREFIX = "CMD";
|
||||
|
||||
private final BlockCommandSender sender;
|
||||
private final WorldEditPlugin plugin;
|
||||
private final Location location;
|
||||
private final UUID uuid;
|
||||
|
||||
public BukkitBlockCommandSender(WorldEditPlugin plugin, BlockCommandSender sender) {
|
||||
super(BukkitAdapter.adapt(checkNotNull(sender).getBlock().getLocation()));
|
||||
checkNotNull(plugin);
|
||||
checkNotNull(sender);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.sender = sender;
|
||||
this.location = BukkitAdapter.adapt(sender.getBlock().getLocation());
|
||||
this.uuid = UUID.nameUUIDFromBytes((UUID_PREFIX + sender.getName()).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@ -134,21 +129,6 @@ public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements
|
||||
return WorldEdit.getInstance().getConfiguration().defaultLocale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLocation(Location location) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return this.location.getExtent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return uuid;
|
||||
|
@ -25,7 +25,6 @@ import com.sk89q.worldedit.util.YAMLConfiguration;
|
||||
import com.sk89q.worldedit.util.report.Unreported;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
@ -36,7 +35,6 @@ public class BukkitConfiguration extends YAMLConfiguration {
|
||||
@Unreported
|
||||
private final WorldEditPlugin plugin;
|
||||
public boolean noOpPermissions = false;
|
||||
public boolean commandBlockSupport = false;
|
||||
public boolean unsupportedVersionEditing = false;
|
||||
|
||||
public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) {
|
||||
@ -48,33 +46,12 @@ public class BukkitConfiguration extends YAMLConfiguration {
|
||||
public void load() {
|
||||
super.load();
|
||||
noOpPermissions = config.getBoolean("no-op-permissions", false);
|
||||
commandBlockSupport = config.getBoolean("command-block-support", false);
|
||||
unsupportedVersionEditing = "I accept that I will receive no support with this flag enabled.".equals(
|
||||
config.getString("allow-editing-on-unsupported-versions", "false"));
|
||||
if (unsupportedVersionEditing) {
|
||||
WorldEdit.logger.warn("Editing without a Bukkit adapter has been enabled. You will not receive support "
|
||||
+ "for any issues that arise as a result.");
|
||||
}
|
||||
migrateLegacyFolders();
|
||||
}
|
||||
|
||||
private void migrateLegacyFolders() {
|
||||
migrate(scriptsDir, "craftscripts");
|
||||
migrate(saveDir, "schematics");
|
||||
migrate("drawings", "draw.js images");
|
||||
}
|
||||
|
||||
private void migrate(String file, String name) {
|
||||
File fromDir = new File(".", file);
|
||||
File toDir = new File(getWorkingDirectoryPath().toFile(), file);
|
||||
if (fromDir.exists() & !toDir.exists()) {
|
||||
if (fromDir.renameTo(toDir)) {
|
||||
plugin.getLogger().info("Migrated " + name + " folder '" + file
|
||||
+ "' from server root to plugin data folder.");
|
||||
} else {
|
||||
plugin.getLogger().warning("Error while migrating " + name + " folder!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,8 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.util.WorldUnloadedException;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||
@ -242,6 +244,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public int getBlockLightLevel(BlockVector3 pt) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(pt);
|
||||
//FAWE end
|
||||
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel();
|
||||
}
|
||||
|
||||
@ -265,6 +270,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
@Override
|
||||
public boolean clearContainerBlockContents(BlockVector3 pt) {
|
||||
checkNotNull(pt);
|
||||
//FAWE start - safe edit region
|
||||
testCoords(pt);
|
||||
//FAWE end
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
try {
|
||||
@ -337,6 +345,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
@Override
|
||||
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 pt) {
|
||||
//FAWE start - allow tree commands to be undone and obey region restrictions
|
||||
testCoords(pt);
|
||||
return WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt, getWorld());
|
||||
//FAWE end
|
||||
}
|
||||
@ -349,6 +358,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public void checkLoadedChunk(BlockVector3 pt) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(pt);
|
||||
//FAWE end
|
||||
World world = getWorld();
|
||||
//FAWE start
|
||||
int X = pt.getBlockX() >> 4;
|
||||
@ -480,6 +492,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public void simulateBlockMine(BlockVector3 pt) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(pt);
|
||||
//FAWE end
|
||||
getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally();
|
||||
}
|
||||
|
||||
@ -493,6 +508,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public boolean canPlaceAt(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState blockState) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.canPlaceAt(getWorld(), position, blockState);
|
||||
@ -505,6 +523,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public com.sk89q.worldedit.world.block.BlockState getBlock(BlockVector3 position) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
try {
|
||||
@ -526,6 +547,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
if (worldNativeAccess != null) {
|
||||
try {
|
||||
return worldNativeAccess.setBlock(position, block, sideEffects);
|
||||
@ -545,6 +569,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.getFullBlock(BukkitAdapter.adapt(getWorld(), position));
|
||||
@ -553,11 +580,25 @@ public class BukkitWorld extends AbstractWorld {
|
||||
}
|
||||
}
|
||||
|
||||
private void testCoords(BlockVector3 position) throws FaweException {
|
||||
if (!Settings.settings().REGION_RESTRICTIONS_OPTIONS.RESTRICT_TO_SAFE_RANGE) {
|
||||
return;
|
||||
}
|
||||
int x = position.getX();
|
||||
int z = position.getZ();
|
||||
if (x > 30000000 || z > 30000000 || x < -30000000 || z < -30000000) {
|
||||
throw FaweCache.OUTSIDE_SAFE_REGION;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> applySideEffects(
|
||||
BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType,
|
||||
SideEffectSet sideEffectSet
|
||||
) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
if (worldNativeAccess != null) {
|
||||
worldNativeAccess.applySideEffects(position, previousType, sideEffectSet);
|
||||
return Sets.intersection(
|
||||
@ -571,6 +612,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public boolean useItem(BlockVector3 position, BaseItem item, Direction face) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
return adapter.simulateItemUse(getWorld(), position, item, face);
|
||||
@ -588,6 +632,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BiomeType getBiome(BlockVector3 position) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
if (HAS_3D_BIOMES) {
|
||||
return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ()));
|
||||
} else {
|
||||
@ -598,6 +645,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean setBiome(BlockVector3 position, BiomeType biome) {
|
||||
//FAWE start - safe edit region
|
||||
testCoords(position);
|
||||
//FAWE end
|
||||
if (HAS_3D_BIOMES) {
|
||||
getWorld().setBiome(position.getBlockX(), position.getBlockY(), position.getBlockZ(), BukkitAdapter.adapt(biome));
|
||||
} else {
|
||||
@ -626,11 +676,13 @@ public class BukkitWorld extends AbstractWorld {
|
||||
|
||||
@Override
|
||||
public void refreshChunk(int chunkX, int chunkZ) {
|
||||
testCoords(BlockVector3.at(chunkX << 4, 0, chunkZ << 4));
|
||||
getWorld().refreshChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int chunkX, int chunkZ) {
|
||||
testCoords(BlockVector3.at(chunkX << 4, 0, chunkZ << 4));
|
||||
return WorldEditPlugin.getInstance().getBukkitImplAdapter().get(getWorldChecked(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
|
@ -112,11 +112,15 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
private BukkitServerInterface platform;
|
||||
private BukkitConfiguration config;
|
||||
private BukkitPermissionAttachmentManager permissionAttachmentManager;
|
||||
// Fawe start
|
||||
private BukkitCommandSender bukkitConsoleCommandSender;
|
||||
// Fawe end
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
//FAWE start
|
||||
this.bukkitConsoleCommandSender = new BukkitCommandSender(this, Bukkit.getConsoleSender());
|
||||
// This is already covered by Spigot, however, a more pesky warning with a proper explanation over "Ambiguous plugin name..." can't hurt.
|
||||
Plugin[] plugins = Bukkit.getServer().getPluginManager().getPlugins();
|
||||
for (Plugin p : plugins) {
|
||||
@ -594,7 +598,7 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
return new BukkitBlockCommandSender(this, (BlockCommandSender) sender);
|
||||
}
|
||||
|
||||
return new BukkitCommandSender(this, sender);
|
||||
return bukkitConsoleCommandSender;
|
||||
}
|
||||
|
||||
public BukkitServerInterface getInternalPlatform() {
|
||||
@ -668,6 +672,13 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
String label = buffer.substring(0, firstSpace);
|
||||
// Strip leading slash, if present.
|
||||
label = label.startsWith("/") ? label.substring(1) : label;
|
||||
|
||||
// If command not owned by FAWE, do not tab complete
|
||||
Plugin owner = platform.getDynamicCommands().getCommandOwner(label);
|
||||
if (owner != WorldEditPlugin.this) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Optional<org.enginehub.piston.Command> command
|
||||
= WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(
|
||||
label);
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.wepif;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@ -30,10 +32,13 @@ import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
@ -158,6 +163,33 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends BanEntry<? super PlayerProfile>> @Nullable E ban(
|
||||
@Nullable final String reason,
|
||||
@Nullable final Instant expires,
|
||||
@Nullable final String source
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends BanEntry<? super PlayerProfile>> @Nullable E ban(
|
||||
@Nullable final String reason,
|
||||
@Nullable final Duration duration,
|
||||
@Nullable final String source
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BanEntry<org.bukkit.profile.PlayerProfile> ban(
|
||||
@Nullable final String reason,
|
||||
@Nullable final Date expires,
|
||||
@Nullable final String source
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@ -323,4 +355,9 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Location getLastDeathLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
public class BukkitWorldTest {
|
||||
|
||||
@Test
|
||||
public void testTreeTypeMapping() {
|
||||
for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) {
|
||||
assertNotNull(BukkitWorld.toBukkitTreeType(type), "No mapping for: " + type);
|
||||
|
@ -27,16 +27,16 @@ dependencies {
|
||||
|
||||
// Minecraft expectations
|
||||
annotationProcessor(libs.guava)
|
||||
implementation("com.google.guava:guava")
|
||||
implementation("com.google.code.gson:gson")
|
||||
implementation(libs.guava)
|
||||
implementation(libs.gson)
|
||||
|
||||
// Logging
|
||||
implementation(libs.log4jBom) {
|
||||
because("We control Log4J on this platform")
|
||||
}
|
||||
implementation("org.apache.logging.log4j:log4j-api")
|
||||
implementation(libs.log4jApi)
|
||||
implementation(libs.log4jCore)
|
||||
implementation("commons-cli:commons-cli:1.5.0")
|
||||
implementation(libs.commonsCli)
|
||||
api(libs.parallelgzip) { isTransitive = false }
|
||||
api(libs.lz4Java)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||
import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.task.Task;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -39,9 +40,12 @@ public class CLIExtraCommands {
|
||||
desc = "Select the entire world"
|
||||
)
|
||||
public void selectWorld(Actor actor, World world, LocalSession session) {
|
||||
session.setRegionSelector(world, new CuboidRegionSelector(
|
||||
world, world.getMinimumPoint(), world.getMaximumPoint()
|
||||
));
|
||||
final CuboidRegionSelector selector;
|
||||
if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) {
|
||||
selector = new ExtendingCuboidRegionSelector(world, world.getMinimumPoint(), world.getMaximumPoint());
|
||||
} else {
|
||||
selector = new CuboidRegionSelector(world, world.getMinimumPoint(), world.getMaximumPoint());
|
||||
}
|
||||
actor.printInfo(TextComponent.of("Selected the entire world."));
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@ applyPlatformAndCoreConfiguration()
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
implementation("org.yaml:snakeyaml") {
|
||||
version { strictly("1.33") }
|
||||
implementation(libs.snakeyaml) {
|
||||
version { strictly("2.0") }
|
||||
because("Bukkit provides SnakeYaml")
|
||||
}
|
||||
}
|
||||
@ -24,17 +24,17 @@ dependencies {
|
||||
|
||||
// Minecraft expectations
|
||||
implementation(libs.fastutil)
|
||||
implementation("com.google.guava:guava")
|
||||
implementation("com.google.code.gson:gson")
|
||||
implementation(libs.guava)
|
||||
implementation(libs.gson)
|
||||
|
||||
// Platform expectations
|
||||
implementation("org.yaml:snakeyaml")
|
||||
implementation(libs.snakeyaml)
|
||||
|
||||
// Logging
|
||||
implementation("org.apache.logging.log4j:log4j-api")
|
||||
implementation(libs.log4jApi)
|
||||
|
||||
// Plugins
|
||||
compileOnly("com.plotsquared:PlotSquared-Core") { isTransitive = false }
|
||||
compileOnly(libs.plotSquaredCore) { isTransitive = false }
|
||||
|
||||
// ensure this is on the classpath for the AP
|
||||
annotationProcessor(libs.guava)
|
||||
@ -45,11 +45,11 @@ dependencies {
|
||||
compileOnly(libs.truezip)
|
||||
implementation(libs.findbugs)
|
||||
implementation(libs.rhino)
|
||||
compileOnly("net.kyori:adventure-api")
|
||||
compileOnly(libs.adventureApi)
|
||||
compileOnlyApi(libs.adventureNbt)
|
||||
compileOnlyApi("net.kyori:adventure-text-minimessage")
|
||||
compileOnlyApi(libs.adventureMiniMessage)
|
||||
implementation(libs.zstd) { isTransitive = false }
|
||||
compileOnly("com.intellectualsites.paster:Paster")
|
||||
compileOnly(libs.paster)
|
||||
compileOnly(libs.lz4Java) { isTransitive = false }
|
||||
compileOnly(libs.sparsebitset)
|
||||
compileOnly(libs.parallelgzip) { isTransitive = false }
|
||||
|
@ -1,14 +1,14 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.5.30"
|
||||
kotlin("jvm") version "1.8.20"
|
||||
application
|
||||
}
|
||||
|
||||
applyCommonConfiguration()
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
kotlinOptions.jvmTarget = "17"
|
||||
}
|
||||
|
||||
application.mainClass.set("com.sk89q.worldedit.internal.util.DocumentationPrinter")
|
||||
|
@ -134,15 +134,29 @@ public class MobSpawnerBlock extends BaseBlock {
|
||||
values.put("MaxNearbyEntities", new ShortTag(maxNearbyEntities));
|
||||
values.put("RequiredPlayerRange", new ShortTag(requiredPlayerRange));
|
||||
if (spawnData == null) {
|
||||
values.put("SpawnData", new CompoundTag(ImmutableMap.of("id", new StringTag(mobType))));
|
||||
values.put(
|
||||
"SpawnData",
|
||||
new CompoundTag(ImmutableMap.of("entity", new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))))
|
||||
);
|
||||
} else {
|
||||
values.put("SpawnData", new CompoundTag(spawnData.getValue()));
|
||||
}
|
||||
if (spawnPotentials == null) {
|
||||
values.put("SpawnPotentials", new ListTag(CompoundTag.class, ImmutableList.of(
|
||||
new CompoundTag(ImmutableMap.of("Weight", new IntTag(1), "Entity",
|
||||
new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))
|
||||
)))));
|
||||
values.put(
|
||||
"SpawnPotentials",
|
||||
new ListTag(
|
||||
CompoundTag.class,
|
||||
ImmutableList.of(new CompoundTag(ImmutableMap.of(
|
||||
"weight",
|
||||
new IntTag(1),
|
||||
"data",
|
||||
new CompoundTag(ImmutableMap.of(
|
||||
"entity",
|
||||
new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))
|
||||
))
|
||||
)))
|
||||
)
|
||||
);
|
||||
} else {
|
||||
values.put("SpawnPotentials", new ListTag(CompoundTag.class, spawnPotentials.getValue()));
|
||||
}
|
||||
|
@ -20,27 +20,29 @@
|
||||
package com.sk89q.worldedit.blocks;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.util.gson.GsonUtil;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Represents a sign block.
|
||||
*
|
||||
* @deprecated WorldEdit does not handle interpreting NBT,
|
||||
* deprecated for removal without replacement
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class SignBlock extends BaseBlock {
|
||||
|
||||
private String[] text;
|
||||
|
||||
private static String EMPTY = "{\"text\":\"\"}";
|
||||
private static final String EMPTY = "{\"text\":\"\"}";
|
||||
|
||||
/**
|
||||
* Construct the sign with text.
|
||||
@ -64,6 +66,11 @@ public class SignBlock extends BaseBlock {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
private boolean isLegacy() {
|
||||
int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion();
|
||||
return dataVersion < Constants.DATA_VERSION_MC_1_20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text.
|
||||
*
|
||||
@ -98,10 +105,17 @@ public class SignBlock extends BaseBlock {
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
values.put("Text1", new StringTag(text[0]));
|
||||
values.put("Text2", new StringTag(text[1]));
|
||||
values.put("Text3", new StringTag(text[2]));
|
||||
values.put("Text4", new StringTag(text[3]));
|
||||
if (isLegacy()) {
|
||||
values.put("Text1", new StringTag(text[0]));
|
||||
values.put("Text2", new StringTag(text[1]));
|
||||
values.put("Text3", new StringTag(text[2]));
|
||||
values.put("Text4", new StringTag(text[3]));
|
||||
} else {
|
||||
ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList()));
|
||||
Map<String, Tag> frontTextTag = new HashMap<>();
|
||||
frontTextTag.put("messages", messages);
|
||||
values.put("front_text", new CompoundTag(frontTextTag));
|
||||
}
|
||||
return new CompoundTag(values);
|
||||
}
|
||||
|
||||
@ -122,24 +136,33 @@ public class SignBlock extends BaseBlock {
|
||||
throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId()));
|
||||
}
|
||||
|
||||
t = values.get("Text1");
|
||||
if (t instanceof StringTag) {
|
||||
text[0] = ((StringTag) t).getValue();
|
||||
}
|
||||
if (isLegacy()) {
|
||||
t = values.get("Text1");
|
||||
if (t instanceof StringTag) {
|
||||
text[0] = ((StringTag) t).getValue();
|
||||
}
|
||||
|
||||
t = values.get("Text2");
|
||||
if (t instanceof StringTag) {
|
||||
text[1] = ((StringTag) t).getValue();
|
||||
}
|
||||
t = values.get("Text2");
|
||||
if (t instanceof StringTag) {
|
||||
text[1] = ((StringTag) t).getValue();
|
||||
}
|
||||
|
||||
t = values.get("Text3");
|
||||
if (t instanceof StringTag) {
|
||||
text[2] = ((StringTag) t).getValue();
|
||||
}
|
||||
t = values.get("Text3");
|
||||
if (t instanceof StringTag) {
|
||||
text[2] = ((StringTag) t).getValue();
|
||||
}
|
||||
|
||||
t = values.get("Text4");
|
||||
if (t instanceof StringTag) {
|
||||
text[3] = ((StringTag) t).getValue();
|
||||
t = values.get("Text4");
|
||||
if (t instanceof StringTag) {
|
||||
text[3] = ((StringTag) t).getValue();
|
||||
}
|
||||
} else {
|
||||
CompoundTag frontTextTag = (CompoundTag) values.get("front_text");
|
||||
ListTag messagesTag = frontTextTag.getListTag("messages");
|
||||
for (int i = 0; i < messagesTag.getValue().size(); i++) {
|
||||
StringTag tag = (StringTag) messagesTag.getValue().get(i);
|
||||
text[i] = tag.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ import com.fastasyncworldedit.core.util.RandomTextureUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TextureUtil;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.task.KeyQueuedExecutorService;
|
||||
import com.github.luben.zstd.Zstd;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
@ -33,6 +35,9 @@ import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -86,6 +91,7 @@ public class Fawe {
|
||||
* The platform specific implementation.
|
||||
*/
|
||||
private final IFawe implementation;
|
||||
private final KeyQueuedExecutorService<UUID> clipboardExecutor;
|
||||
private FaweVersion version;
|
||||
private TextureUtil textures;
|
||||
private QueueHandler queueHandler;
|
||||
@ -131,6 +137,15 @@ public class Fawe {
|
||||
}, 0);
|
||||
|
||||
TaskManager.taskManager().repeat(timer, 1);
|
||||
|
||||
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
|
||||
1,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS,
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new ThreadFactoryBuilder().setNameFormat("fawe-clipboard-%d").build()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,9 +354,10 @@ public class Fawe {
|
||||
Settings.settings().QUEUE.TARGET_SIZE,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS
|
||||
);
|
||||
if (Settings.settings().QUEUE.TARGET_SIZE < 2 * Settings.settings().QUEUE.PARALLEL_THREADS) {
|
||||
if (Settings.settings().QUEUE.TARGET_SIZE < 4 * Settings.settings().QUEUE.PARALLEL_THREADS) {
|
||||
LOGGER.error(
|
||||
"queue.target_size is {}, and queue.parallel_threads is {}. It is HIGHLY recommended that queue" + ".target_size be at least twice queue.parallel_threads or higher.",
|
||||
"queue.target-size is {}, and queue.parallel_threads is {}. It is HIGHLY recommended that queue" +
|
||||
".target-size be at least four times queue.parallel-threads or greater.",
|
||||
Settings.settings().QUEUE.TARGET_SIZE,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS
|
||||
);
|
||||
@ -427,4 +443,14 @@ public class Fawe {
|
||||
return this.thread = Thread.currentThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the executor used for clipboard IO if clipboard on disk is enabled or null
|
||||
*
|
||||
* @return Executor used for clipboard IO if clipboard on disk is enabled or null
|
||||
* @since 2.6.2
|
||||
*/
|
||||
public KeyQueuedExecutorService<UUID> getClipboardExecutor() {
|
||||
return this.clipboardExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -171,52 +171,68 @@ public enum FaweCache implements Trimable {
|
||||
public static final FaweBlockBagException BLOCK_BAG = new FaweBlockBagException();
|
||||
public static final FaweException MANUAL = new FaweException(
|
||||
Caption.of("fawe.cancel.reason.manual"),
|
||||
Type.MANUAL
|
||||
Type.MANUAL,
|
||||
false
|
||||
);
|
||||
public static final FaweException NO_REGION = new FaweException(
|
||||
Caption.of("fawe.cancel.reason.no.region"),
|
||||
Type.NO_REGION
|
||||
Type.NO_REGION,
|
||||
false
|
||||
);
|
||||
public static final FaweException OUTSIDE_REGION = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.outside.region"),
|
||||
Type.OUTSIDE_REGION,
|
||||
true
|
||||
);
|
||||
public static final FaweException OUTSIDE_SAFE_REGION = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.outside.safe.region"),
|
||||
Type.OUTSIDE_REGION
|
||||
);
|
||||
public static final FaweException MAX_CHECKS = new FaweException(
|
||||
Caption.of("fawe.cancel.reason.max" + ".checks"),
|
||||
Type.MAX_CHECKS
|
||||
Type.MAX_CHECKS,
|
||||
true
|
||||
);
|
||||
public static final FaweException MAX_CHANGES = new FaweException(
|
||||
Caption.of("fawe.cancel.reason.max" + ".changes"),
|
||||
Type.MAX_CHANGES
|
||||
Type.MAX_CHANGES,
|
||||
false
|
||||
);
|
||||
public static final FaweException LOW_MEMORY = new FaweException(
|
||||
Caption.of("fawe.cancel.reason.low" + ".memory"),
|
||||
Type.LOW_MEMORY
|
||||
Type.LOW_MEMORY,
|
||||
false
|
||||
);
|
||||
public static final FaweException MAX_ENTITIES = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.max.entities"),
|
||||
Type.MAX_ENTITIES
|
||||
Type.MAX_ENTITIES,
|
||||
true
|
||||
);
|
||||
public static final FaweException MAX_TILES = new FaweException(Caption.of(
|
||||
"fawe.cancel.reason.max.tiles",
|
||||
Type.MAX_TILES
|
||||
Type.MAX_TILES,
|
||||
true
|
||||
));
|
||||
public static final FaweException MAX_ITERATIONS = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.max.iterations"),
|
||||
Type.MAX_ITERATIONS
|
||||
Type.MAX_ITERATIONS,
|
||||
true
|
||||
);
|
||||
public static final FaweException PLAYER_ONLY = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.player-only"),
|
||||
Type.PLAYER_ONLY
|
||||
Type.PLAYER_ONLY,
|
||||
false
|
||||
);
|
||||
public static final FaweException ACTOR_REQUIRED = new FaweException(
|
||||
Caption.of(
|
||||
"fawe.cancel.reason.actor-required"),
|
||||
Type.ACTOR_REQUIRED
|
||||
Type.ACTOR_REQUIRED,
|
||||
false
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.fastasyncworldedit.core.command;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
@ -13,33 +15,81 @@ public class SuggestInputParseException extends InputParseException {
|
||||
|
||||
private final InputParseException cause;
|
||||
private final Supplier<List<String>> getSuggestions;
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SuggestInputParseException#SuggestInputParseException(Component, Supplier)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.6.2")
|
||||
public SuggestInputParseException(String msg, String prefix, Supplier<List<String>> getSuggestions) {
|
||||
this(new InputParseException(msg), prefix, getSuggestions);
|
||||
this(new InputParseException(msg), getSuggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SuggestInputParseException#of(Throwable, Supplier)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.6.2")
|
||||
public static SuggestInputParseException of(Throwable other, String prefix, Supplier<List<String>> getSuggestions) {
|
||||
if (other instanceof InputParseException) {
|
||||
return of((InputParseException) other, prefix, getSuggestions);
|
||||
return of((InputParseException) other, getSuggestions);
|
||||
}
|
||||
return of(new InputParseException(other.getMessage()), prefix, getSuggestions);
|
||||
return of(new InputParseException(other.getMessage()), getSuggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SuggestInputParseException#of(InputParseException, Supplier)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.6.2")
|
||||
public static SuggestInputParseException of(InputParseException other, String prefix, Supplier<List<String>> getSuggestions) {
|
||||
if (other instanceof SuggestInputParseException) {
|
||||
return (SuggestInputParseException) other;
|
||||
}
|
||||
return new SuggestInputParseException(other, prefix, getSuggestions);
|
||||
return new SuggestInputParseException(other, getSuggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SuggestInputParseException#SuggestInputParseException(InputParseException, Supplier)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.6.2")
|
||||
public SuggestInputParseException(InputParseException other, String prefix, Supplier<List<String>> getSuggestions) {
|
||||
super(other.getMessage());
|
||||
super(other.getRichMessage());
|
||||
checkNotNull(getSuggestions);
|
||||
checkNotNull(other);
|
||||
this.cause = other;
|
||||
this.getSuggestions = getSuggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SuggestInputParseException instance
|
||||
*
|
||||
* @param message Message to send
|
||||
* @param getSuggestions Supplier of list of suggestions to give to user
|
||||
* @since 2.6.2
|
||||
*/
|
||||
public SuggestInputParseException(Component message, Supplier<List<String>> getSuggestions) {
|
||||
this(new InputParseException(message), getSuggestions);
|
||||
}
|
||||
|
||||
public static SuggestInputParseException of(Throwable other, Supplier<List<String>> getSuggestions) {
|
||||
if (other instanceof InputParseException) {
|
||||
return of((InputParseException) other, getSuggestions);
|
||||
}
|
||||
//noinspection deprecation
|
||||
return of(new InputParseException(other.getMessage()), getSuggestions);
|
||||
}
|
||||
|
||||
public static SuggestInputParseException of(InputParseException other, Supplier<List<String>> getSuggestions) {
|
||||
if (other instanceof SuggestInputParseException) {
|
||||
return (SuggestInputParseException) other;
|
||||
}
|
||||
return new SuggestInputParseException(other, getSuggestions);
|
||||
}
|
||||
|
||||
public SuggestInputParseException(InputParseException other, Supplier<List<String>> getSuggestions) {
|
||||
super(other.getRichMessage());
|
||||
checkNotNull(getSuggestions);
|
||||
checkNotNull(other);
|
||||
this.cause = other;
|
||||
this.getSuggestions = getSuggestions;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public static SuggestInputParseException get(InvocationTargetException e) {
|
||||
@ -54,7 +104,7 @@ public class SuggestInputParseException extends InputParseException {
|
||||
}
|
||||
|
||||
public static SuggestInputParseException of(String input, List<Object> values) {
|
||||
throw new SuggestInputParseException("No value: " + input, input, () ->
|
||||
throw new SuggestInputParseException(Caption.of("fawe.error.no-value-for-input", input), () ->
|
||||
values.stream()
|
||||
.map(Object::toString)
|
||||
.filter(v -> v.startsWith(input))
|
||||
@ -76,8 +126,12 @@ public class SuggestInputParseException extends InputParseException {
|
||||
return getSuggestions.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unused
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.6.2")
|
||||
public SuggestInputParseException prepend(String input) {
|
||||
this.prefix = input + prefix;
|
||||
// Do nothing
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,27 @@ import java.util.List;
|
||||
public class CommandBrush implements Brush {
|
||||
|
||||
private final String command;
|
||||
private final boolean print;
|
||||
|
||||
/**
|
||||
* New instance
|
||||
*
|
||||
* @deprecated Use {@link CommandBrush#CommandBrush(String, boolean)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public CommandBrush(String command) {
|
||||
this.command = command.charAt(0) == '/' ? "/" + command : command;
|
||||
this(command, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* New instance
|
||||
*
|
||||
* @param command command to run, or commands split by ';'
|
||||
* @param print if output should be printed to the actor for the run commands
|
||||
*/
|
||||
public CommandBrush(String command, boolean print) {
|
||||
this.command = command;
|
||||
this.print = print;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,7 +54,7 @@ public class CommandBrush implements Brush {
|
||||
position.subtract(radius, radius, radius),
|
||||
position.add(radius, radius, radius)
|
||||
);
|
||||
String replaced = command.replace("{x}", position.getBlockX() + "")
|
||||
String replaced = command.replace("{x}", Integer.toString(position.getBlockX()))
|
||||
.replace("{y}", Integer.toString(position.getBlockY()))
|
||||
.replace("{z}", Integer.toString(position.getBlockZ()))
|
||||
.replace("{world}", editSession.getWorld().getName())
|
||||
@ -46,21 +64,22 @@ public class CommandBrush implements Brush {
|
||||
if (!(actor instanceof Player player)) {
|
||||
throw FaweCache.PLAYER_ONLY;
|
||||
}
|
||||
//Use max world height to allow full coverage of the world height
|
||||
Location face = player.getBlockTraceFace(editSession.getWorld().getMaxY(), true);
|
||||
if (face == null) {
|
||||
position = position.add(0, 1, 1);
|
||||
} else {
|
||||
position = position.add(face.getDirection().toBlockPoint());
|
||||
}
|
||||
player.setSelection(selector);
|
||||
AsyncPlayer wePlayer = new SilentPlayerWrapper(new LocationMaskedPlayerWrapper(
|
||||
AsyncPlayer wePlayer = new LocationMaskedPlayerWrapper(
|
||||
player,
|
||||
new Location(player.getExtent(), position.toVector3())
|
||||
));
|
||||
);
|
||||
if (!print) {
|
||||
wePlayer = new SilentPlayerWrapper(wePlayer);
|
||||
}
|
||||
List<String> cmds = StringMan.split(replaced, ';');
|
||||
for (String cmd : cmds) {
|
||||
CommandEvent event = new CommandEvent(wePlayer, cmd);
|
||||
if (cmd.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
cmd = cmd.charAt(0) != '/' ? "/" + cmd : cmd;
|
||||
cmd = cmd.length() >1 && cmd.charAt(1) == '/' ? cmd.substring(1) : cmd;
|
||||
CommandEvent event = new CommandEvent(wePlayer, cmd, editSession);
|
||||
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package com.fastasyncworldedit.core.command.tool.brush;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
|
||||
import com.fastasyncworldedit.core.util.StringMan;
|
||||
import com.fastasyncworldedit.core.wrappers.AsyncPlayer;
|
||||
import com.fastasyncworldedit.core.wrappers.LocationMaskedPlayerWrapper;
|
||||
import com.fastasyncworldedit.core.wrappers.SilentPlayerWrapper;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
@ -13,7 +15,7 @@ import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -43,7 +45,7 @@ public class ScatterCommand extends ScatterBrush {
|
||||
position.subtract(radius, radius, radius),
|
||||
position.add(radius, radius, radius)
|
||||
);
|
||||
String replaced = command.replace("{x}", position.getBlockX() + "")
|
||||
String replaced = command.replace("{x}", Integer.toString(position.getBlockX()))
|
||||
.replace("{y}", Integer.toString(position.getBlockY()))
|
||||
.replace("{z}", Integer.toString(position.getBlockZ()))
|
||||
.replace("{world}", editSession.getWorld().getName())
|
||||
@ -55,41 +57,22 @@ public class ScatterCommand extends ScatterBrush {
|
||||
}
|
||||
player.setSelection(selector);
|
||||
List<String> cmds = StringMan.split(replaced, ';');
|
||||
AsyncPlayer wePlayer = new LocationMaskedPlayerWrapper(
|
||||
player,
|
||||
new Location(player.getExtent(), position.toVector3())
|
||||
);
|
||||
if (!print) {
|
||||
wePlayer = new SilentPlayerWrapper(wePlayer);
|
||||
}
|
||||
for (String cmd : cmds) {
|
||||
Player p = print ?
|
||||
new LocationMaskedPlayerWrapper(player, player.getLocation().setPosition(position.toVector3()), false) :
|
||||
new ScatterCommandPlayerWrapper(player, position);
|
||||
CommandEvent event = new CommandEvent(p, cmd, editSession);
|
||||
if (cmd.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
cmd = cmd.charAt(0) != '/' ? "/" + cmd : cmd;
|
||||
cmd = cmd.length() >1 && cmd.charAt(1) == '/' ? cmd.substring(1) : cmd;
|
||||
CommandEvent event = new CommandEvent(wePlayer, cmd, editSession);
|
||||
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ScatterCommandPlayerWrapper extends LocationMaskedPlayerWrapper {
|
||||
|
||||
ScatterCommandPlayerWrapper(Player player, BlockVector3 position) {
|
||||
super(player, player.getLocation().setPosition(position.toVector3()), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Component component) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDebug(String msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printError(String msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printRaw(String msg) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,119 +0,0 @@
|
||||
package com.fastasyncworldedit.core.concurrent;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
|
||||
/**
|
||||
* Allows for reentrant behaviour of a wrapped {@link StampedLock}. Will not count the number of times it is re-entered.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class ReentrantWrappedStampedLock implements Lock {
|
||||
|
||||
private final StampedLock parent = new StampedLock();
|
||||
private volatile Thread owner;
|
||||
private volatile long stamp = 0;
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if (Thread.currentThread() == owner) {
|
||||
return;
|
||||
}
|
||||
stamp = parent.writeLock();
|
||||
owner = Thread.currentThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockInterruptibly() throws InterruptedException {
|
||||
if (Thread.currentThread() == owner) {
|
||||
return;
|
||||
}
|
||||
stamp = parent.writeLockInterruptibly();
|
||||
owner = Thread.currentThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if (Thread.currentThread() == owner) {
|
||||
return true;
|
||||
}
|
||||
if (parent.isWriteLocked()) {
|
||||
return false;
|
||||
}
|
||||
stamp = parent.writeLock();
|
||||
owner = Thread.currentThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(final long time, @NotNull final TimeUnit unit) throws InterruptedException {
|
||||
if (Thread.currentThread() == owner) {
|
||||
return true;
|
||||
}
|
||||
if (!parent.isWriteLocked()) {
|
||||
stamp = parent.writeLock();
|
||||
owner = Thread.currentThread();
|
||||
return true;
|
||||
}
|
||||
stamp = parent.tryWriteLock(time, unit);
|
||||
owner = Thread.currentThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if (owner != Thread.currentThread()) {
|
||||
throw new IllegalCallerException("The lock should only be unlocked by the owning thread when a stamp is not supplied");
|
||||
}
|
||||
unlock(stamp);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Condition newCondition() {
|
||||
throw new UnsupportedOperationException("Conditions are not supported by StampedLock");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the stamp associated with the current lock. 0 if the wrapped {@link StampedLock} is not write-locked. This method is
|
||||
* thread-checking.
|
||||
*
|
||||
* @return lock stam[ or 0 if not locked.
|
||||
* @throws IllegalCallerException if the {@link StampedLock} is write-locked and the calling thread is not the lock owner
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public long getStampChecked() {
|
||||
if (stamp != 0 && owner != Thread.currentThread()) {
|
||||
throw new IllegalCallerException("The stamp should be be acquired by a thread that does not own the lock");
|
||||
}
|
||||
return stamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the wrapped {@link StampedLock} using the given stamp. This can be called by any thread.
|
||||
*
|
||||
* @param stamp Stamp to unlock with
|
||||
* @throws IllegalMonitorStateException if the given stamp does not match the lock's stamp
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public void unlock(final long stamp) {
|
||||
parent.unlockWrite(stamp);
|
||||
this.stamp = 0;
|
||||
owner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the lock is currently held.
|
||||
*
|
||||
* @return true if the lock is currently held.
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return owner == null && this.stamp == 0 && parent.isWriteLocked(); // Be verbose
|
||||
}
|
||||
|
||||
}
|
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