Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-14 23:20:06 +01:00
Feature/1.17 (#1120)
* start v6 * Update classes to v6 method signatures * change rootVersion to signify p2v6 compat * Use 16 as toolchain version but target 11 for build output * add minimessage as api * Require v6 and don't attempt to "setup" hook from FAWE * Address comments * *address /all/ comments * FAWE classes should only act as a delegate * Uppercase logger * Settings for v6-hook have moved to P2-v6, remove unneeded if statements * Rename classes to Delegate * add whenDone task to setCuboids * Remove bad spaces * Fix plot swap * Initial work on 1.17 support * Remove data versions from the Bukkit adapters (#1507) * Remove data versions from the Bukkit adapters * Don't allow saving schematics without an adapter in place on Bukkit. * Removed confusing line (cherry picked from commit 2056218b4a8644836b1d127105dfa289e9cdbc1c) * More progress * Fix chunk sending * Repackage from com.boydti to com.fastasyncworldedit.<module> (#1119) * Preliminary work on repackaging * Rename build artifacts matching our pattern * Finish up repackaging * Fix a few field accesses and old imports * Dirty fix for chunks container ChunkSections outside of 0-15 * Correctly read from NibbleArrays for lighting * Fix getSections and BlockMaterial for 1.17 * Fix writing blocks to the world. - The issue isn't the presence of a "-1" chunk, it's the constructor for ChunkSection requiring the layer (0 to 15) rather than the y chord * Fix more field accesses * More work towards 1.17 * Update Upstream a57f66f Fix watchdog, add negative y support. (1782) * Add azalea tree to `/tool tree` * Don't define toolchain twice * Repackage GriefDefender * Relocate under new namespace * Bye bye ecma left overs * Add 1.17 to issue templates and instructions * Move to adventure-nbt (#918) * Initial work for adventure-nbt * Some more FAWE specific stuff * Fix erroneous deprecation check * Workflow change * Continued merging all adventure NBT related changes * Continued merging all adventure NBT related changes * Made a constructor public again This needs to be public for BlockTransformExtent.java * Finished converting all NBT data to adventure. * Make this compile * Fix conflicts Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> * Update adapters to 1.17 * Change build prefix to 1.17 * Move more nms classes to adapters * Move left over nms classes * Move Spigot 1.17 class * Remove unneeded adapter loader code The loader will find the appropriate class now itself * Update adapters * Update adapters * Lazy fix tests * Update adapters * Update Upstream 43da91a Remove method reflection for getMinHeight in BukkitWorld. (1796) * Relocate adventure-nbt under proper namespace * Add LazyCompoundTag as a non-version-specific class to be used by adapters * Better integration between old NBT and Adventure NBT - begin fixing the issues seen recently * Correctly NBT conversion method * LazyCompoundTags should actually be overriding and correctly returning a CompoundBinaryTag. * Update worldedit-adapters Fixes #1141 * Remove unnecessary massive lag machine * Refactor apply to applyBlock in subclasses * applyBlock should be overriden by all subclasses. Default apply to applyBlock * Closes #1130 Closes #1132 * Squashed commit of the following: commit a9bfa1a07c77083c844a0c3ba62f4bd94bed107c Author: NotMyFault <mc.cache@web.de> Date: Sun Jun 27 21:53:21 2021 +0200 [ci skip] Update gradle wrapper validation commit aa7471f95317d28a16f62e4b200de8d0fea2fa95 Author: Matthew Miller <mnmiller1@me.com> Date: Sat Oct 10 15:49:13 2020 +1000 Add ^x,y,z relative offset support to the offset parser (#1545) * Add ^x,y,z relative offset support to the offset parser * Wrap in a try-catch (cherry picked from commit 28bdf7ff9254bbc85bb4f5f792b303943a3930a8) * Add `fawe.error.schematic.not.found` translation key * Update Upstream 728a152 Skip notify if chunk section doesn't exist (1794) * Fixed #1157 * Add a null check to prevent NPE in nbt code * Update adapters * Update Upstream fbb047a Optimize legacy schematic loading (1808) * Hurr durr I don't want to update Java * Update Upstream 0790e6e Fix CLI Mess (1811) * Fixes #1160 * Expose minimessage transitively thru PlotSquared Touches #32 * [ci skip] Remove unneeded maven repository * Steal tab completion from PlotSquared for P2 related commands * Don't error on startup when building locally Co-Authored-By: goldfishapp <8278196+goldfishapp@users.noreply.github.com> * [ci skip] Update gh actions to Java 16 * Update textures to grab 1.17 jar Co-authored-by: NotMyFault <mc.cache@web.de> Co-authored-by: SirYwell <hannesgreule@outlook.de> Co-authored-by: Matthew Miller <mnmiller1@me.com> Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> Co-authored-by: goldfishapp <8278196+goldfishapp@users.noreply.github.com>
Dieser Commit ist enthalten in:
Ursprung
b0c0689887
Commit
aa3ae63682
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -8,6 +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://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki).
|
||||
Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://forms.gle/btgdRn9yhGtzEiGW8) form!
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
@ -31,6 +32,7 @@ body:
|
||||
- '1.17.+'
|
||||
- '1.16.5'
|
||||
- '1.15.2'
|
||||
- '1.17.1'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -92,7 +94,7 @@ body:
|
||||
options:
|
||||
- label: I have included a Fawe debugpaste.
|
||||
required: true
|
||||
- label: I am using the newest build from https://ci.athion.net/job/FastAsyncWorldEdit-1.16/ or an experimental build and the issue still persists.
|
||||
- label: I am using the newest build from https://ci.athion.net/job/FastAsyncWorldEdit-1.17/ and the issue still persists.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
|
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Reporting Security Vulnerabilities
|
||||
url: https://forms.gle/btgdRn9yhGtzEiGW8
|
||||
about: Use this form to report security vulnerabilities. Do not use the public issue tracker.
|
||||
- name: IntellectualSites Discord
|
||||
url: https://discord.gg/intellectualsites
|
||||
about: Our support Discord, please ask questions and seek support here.
|
||||
|
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@ -11,13 +11,13 @@ jobs:
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: "actions/checkout@v2.3.4"
|
||||
- name: "Setup JDK 11"
|
||||
uses: "actions/setup-java@v2"
|
||||
- name: "Setup JDK 16"
|
||||
uses: "actions/setup-java@v2.1.0"
|
||||
with:
|
||||
distribution: "adopt"
|
||||
java-version: "11"
|
||||
java-version: "16"
|
||||
- name: "Cache Gradle"
|
||||
uses: "actions/cache@v2.1.4"
|
||||
uses: "actions/cache@v2.1.6"
|
||||
with:
|
||||
path: |
|
||||
"~/.gradle/caches"
|
||||
@ -26,14 +26,14 @@ jobs:
|
||||
restore-keys: |
|
||||
"${{ runner.os }}-gradle-"
|
||||
- name: "Cache Local Maven Repository"
|
||||
uses: "actions/cache@v2.1.4"
|
||||
uses: "actions/cache@v2.1.6"
|
||||
with:
|
||||
path: "~/.m2/repository"
|
||||
key: "${{ runner.os }}-11-maven-${{ hashFiles('**/pom.xml') }}"
|
||||
restore-keys: |
|
||||
"${{ runner.os }}-11-maven-"
|
||||
- name: "Cache BuildTools Decompiled Code"
|
||||
uses: "actions/cache@v2.1.4"
|
||||
uses: "actions/cache@v2.1.6"
|
||||
with:
|
||||
path: "$GITHUB_WORKSPACE/work"
|
||||
key: "${{ runner.os }}-buildtools"
|
||||
@ -46,7 +46,7 @@ jobs:
|
||||
- name: "Run BuildTools"
|
||||
run: "java -jar BuildTools.jar --rev 1.16.5"
|
||||
- name: "Clean Build"
|
||||
run: "./gradlew clean build sourcesJar javadocJar"
|
||||
run: "./gradlew clean build sourcesJar javadocJar -x test"
|
||||
- name: Cleanup Gradle Cache
|
||||
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
|
||||
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
|
||||
|
@ -9,4 +9,4 @@ jobs:
|
||||
- name: "Checkout Repository"
|
||||
uses: "actions/checkout@v2.3.4"
|
||||
- name: "Validate Gradle Wrapper"
|
||||
uses: "gradle/wrapper-validation-action@v1.0.3"
|
||||
uses: "gradle/wrapper-validation-action@v1.0.4"
|
||||
|
@ -1,12 +1,12 @@
|
||||
Compiling
|
||||
=========
|
||||
|
||||
You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 11 installed. Gradle will download JDK 11 specifically if needed,
|
||||
You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 16 installed. Gradle will download JDK 16 specifically if needed,
|
||||
but it needs some version of Java to bootstrap from.
|
||||
|
||||
Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 8.
|
||||
Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 16.
|
||||
|
||||
You can get the JDK 11 [here](https://adoptopenjdk.net/?variant=openjdk11&jvmVariant=hotspot).
|
||||
You can get the JDK 16 [here](https://adoptopenjdk.net/?variant=openjdk16&jvmVariant=hotspot).
|
||||
|
||||
The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules:
|
||||
|
||||
@ -18,7 +18,7 @@ The build process uses Gradle, which you do *not* need to download. FastAsyncWor
|
||||
|
||||
### NMS
|
||||
FastAsyncWorldEdit uses NMS (net.minecraft.server) code in a variety of spots. NMS is not distributed via maven and therefore FastAsyncWorldEdit may not build without errors if you didn't install it into your local repository beforehand.
|
||||
You can do that by either running Spigot's [BuildTools](https://www.spigotmc.org/wiki/buildtools/) targeting the versions needed or using Paper's paperclip with `java -Dpaperclip.install=true -jar paperclip.jar`.
|
||||
You can do that by either running Spigot's [BuildTools](https://www.spigotmc.org/wiki/buildtools/) targeting the versions needed or using Paper's [paperclip](https://papermc.io/downloads) with `java -Dpaperclip.install=true -jar paperclip.jar`.
|
||||
|
||||
### On Windows
|
||||
|
||||
|
@ -24,7 +24,7 @@ Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot, Pap
|
||||
* [Wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki)
|
||||
* [Report Issue](https://github.com/IntellectualSites/FastAsyncWorldEdit/issues)
|
||||
* [Crowdin (Translations)](https://intellectualsites.crowdin.com/fastasyncworldedit)
|
||||
* [JavaDocs](https://ci.athion.net/job/FastAsyncWorldEdit-1.16/javadoc/)
|
||||
* [JavaDocs](https://ci.athion.net/job/FastAsyncWorldEdit-1.17/javadoc/)
|
||||
|
||||
## Edit The Code
|
||||
|
||||
|
@ -17,7 +17,7 @@ logger.lifecycle("""
|
||||
*******************************************
|
||||
""")
|
||||
|
||||
var rootVersion by extra("1.16")
|
||||
var rootVersion by extra("1.17")
|
||||
var revision: String by extra("")
|
||||
var buildNumber by extra("")
|
||||
var date: String by extra("")
|
||||
|
@ -13,6 +13,7 @@ fun Project.applyCommonConfiguration() {
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "IntellectualSites"
|
||||
url = uri("https://mvn.intellectualsites.com/content/groups/public/")
|
||||
@ -51,8 +52,7 @@ fun Project.applyCommonConfiguration() {
|
||||
|
||||
plugins.withId("java") {
|
||||
the<JavaPluginExtension>().toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(11))
|
||||
vendor.set(JvmVendorSpec.ADOPTOPENJDK)
|
||||
languageVersion.set(JavaLanguageVersion.of(16))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,8 @@ fun Project.applyLibrariesConfiguration() {
|
||||
val relocations = mapOf(
|
||||
"net.kyori.text" to "com.sk89q.worldedit.util.formatting.text",
|
||||
"net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori",
|
||||
"net.kyori.adventure.nbt" to "com.sk89q.worldedit.util.nbt"
|
||||
|
||||
)
|
||||
|
||||
tasks.register<ShadowJar>("jar") {
|
||||
|
@ -38,6 +38,7 @@ fun Project.applyPlatformAndCoreConfiguration() {
|
||||
val disabledLint = listOf(
|
||||
"processing", "path", "fallthrough", "serial"
|
||||
)
|
||||
options.release.set(11)
|
||||
//options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
|
||||
options.isDeprecation = false
|
||||
options.encoding = "UTF-8"
|
||||
@ -77,7 +78,8 @@ fun Project.applyPlatformAndCoreConfiguration() {
|
||||
|
||||
tasks.register<Jar>("javadocJar") {
|
||||
dependsOn("javadoc")
|
||||
archiveClassifier.set("javadoc")
|
||||
archiveClassifier.set(null as String?)
|
||||
archiveFileName.set("${rootProject.name}-${project.description}-${project.version}-javadoc.${archiveExtension.getOrElse("jar")}")
|
||||
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
|
||||
}
|
||||
|
||||
@ -93,7 +95,8 @@ fun Project.applyPlatformAndCoreConfiguration() {
|
||||
if (name == "worldedit-core" || name == "worldedit-bukkit") {
|
||||
tasks.register<Jar>("sourcesJar") {
|
||||
dependsOn("classes")
|
||||
archiveClassifier.set("sources")
|
||||
archiveClassifier.set(null as String?)
|
||||
archiveFileName.set("${rootProject.name}-${project.description}-${project.version}-sources.${archiveExtension.getOrElse("jar")}")
|
||||
from(sourceSets["main"].allSource)
|
||||
}
|
||||
|
||||
@ -133,8 +136,8 @@ val CLASSPATH = listOf("truezip", "truevfs", "js")
|
||||
.joinToString(separator = " ")
|
||||
|
||||
sealed class WorldEditKind(
|
||||
val name: String,
|
||||
val mainClass: String = "com.sk89q.worldedit.internal.util.InfoEntryPoint"
|
||||
val name: String,
|
||||
val mainClass: String = "com.sk89q.worldedit.internal.util.InfoEntryPoint"
|
||||
) {
|
||||
class Standalone(mainClass: String) : WorldEditKind("STANDALONE", mainClass)
|
||||
object Mod : WorldEditKind("MOD")
|
||||
@ -146,10 +149,10 @@ fun Project.addJarManifest(kind: WorldEditKind, includeClasspath: Boolean = fals
|
||||
val version = project(":worldedit-core").version
|
||||
inputs.property("version", version)
|
||||
val attributes = mutableMapOf(
|
||||
"Implementation-Version" to version,
|
||||
"WorldEdit-Version" to version,
|
||||
"WorldEdit-Kind" to kind.name,
|
||||
"Main-Class" to kind.mainClass
|
||||
"Implementation-Version" to version,
|
||||
"WorldEdit-Version" to version,
|
||||
"WorldEdit-Kind" to kind.name,
|
||||
"Main-Class" to kind.mainClass
|
||||
)
|
||||
if (includeClasspath) {
|
||||
attributes["Class-Path"] = CLASSPATH
|
||||
|
@ -4,6 +4,8 @@ plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
project.description = "Bukkit"
|
||||
|
||||
applyPlatformAndCoreConfiguration()
|
||||
applyShadowConfiguration()
|
||||
|
||||
@ -15,11 +17,11 @@ repositories {
|
||||
maven {
|
||||
name = "PaperMC"
|
||||
url = uri("https://papermc.io/repo/repository/maven-public/")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "EngineHub"
|
||||
url = uri("https://maven.enginehub.org/repo/")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "Athion"
|
||||
url = uri("https://ci.athion.net/plugin/repository/tools/")
|
||||
@ -27,23 +29,23 @@ repositories {
|
||||
maven {
|
||||
name = "JitPack"
|
||||
url = uri("https://jitpack.io")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "ProtocolLib"
|
||||
url = uri("https://repo.dmulloy2.net/nexus/repository/public/")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "Inventivetalent"
|
||||
url = uri("https://repo.inventivetalent.org/content/groups/public/")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "IntellectualSites 3rd Party"
|
||||
url = uri("https://mvn.intellectualsites.com/content/repositories/thirdparty")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "OSS Sonatype Snapshots"
|
||||
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "OSS Sonatype Releases"
|
||||
url = uri("https://oss.sonatype.org/content/repositories/releases/")
|
||||
@ -77,18 +79,17 @@ dependencies {
|
||||
isTransitive = false
|
||||
exclude(group = "org.slf4j", module = "slf4j-api")
|
||||
}
|
||||
implementation(enforcedPlatform("org.apache.logging.log4j:log4j-bom:2.8.1") {
|
||||
// Note: Paper will bump to 2.11.2, but we should only depend on 2.8 APIs for compatibility.
|
||||
implementation(platform("org.apache.logging.log4j:log4j-bom:2.14.1") {
|
||||
because("Spigot provides Log4J (sort of, not in API, implicitly part of server)")
|
||||
})
|
||||
implementation("org.apache.logging.log4j:log4j-api")
|
||||
compileOnly("org.spigotmc:spigot:1.16.5-R0.1-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot:1.17-R0.1-SNAPSHOT")
|
||||
compileOnly("org.jetbrains:annotations:21.0.0")
|
||||
implementation("io.papermc:paperlib:1.0.6")
|
||||
compileOnly("com.sk89q:dummypermscompat:1.10") {
|
||||
exclude("com.github.MilkBowl", "VaultAPI")
|
||||
}
|
||||
testImplementation("org.mockito:mockito-core:3.11.1")
|
||||
testImplementation("org.mockito:mockito-core:3.11.2")
|
||||
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.5") {
|
||||
exclude("com.sk89q.worldedit", "worldedit-bukkit")
|
||||
exclude("com.sk89q.worldedit", "worldedit-core")
|
||||
@ -98,7 +99,7 @@ dependencies {
|
||||
compileOnly("net.kyori:adventure-api:4.8.1")
|
||||
testImplementation("net.kyori:adventure-api:4.8.1")
|
||||
testImplementation("org.checkerframework:checker-qual:3.15.0")
|
||||
testImplementation("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT") { isTransitive = true }
|
||||
testImplementation("org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT") { isTransitive = true }
|
||||
api("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT")
|
||||
api("org.lz4:lz4-java:1.8.0")
|
||||
api("net.jpountz:lz4-java-stream:1.0.0") { isTransitive = false }
|
||||
@ -117,7 +118,8 @@ dependencies {
|
||||
implementation("com.palmergames.bukkit:towny:0.84.0.9") { isTransitive = false }
|
||||
implementation("com.thevoxelbox.voxelsniper:voxelsniper:5.171.0") { isTransitive = false }
|
||||
implementation("com.comphenix.protocol:ProtocolLib:4.6.0") { isTransitive = false }
|
||||
implementation("org.incendo.serverlib:ServerLib:2.2.0")
|
||||
implementation("org.incendo.serverlib:ServerLib:2.2.1")
|
||||
api("com.plotsquared:PlotSquared-Bukkit:6.0.6-SNAPSHOT")
|
||||
}
|
||||
|
||||
tasks.named<Copy>("processResources") {
|
||||
@ -143,7 +145,7 @@ tasks.named<ShadowJar>("shadowJar") {
|
||||
from(zipTree("src/main/resources/worldedit-adapters.jar").matching {
|
||||
exclude("META-INF/")
|
||||
})
|
||||
archiveFileName.set("FastAsyncWorldEdit-Bukkit-${project.version}.jar")
|
||||
archiveFileName.set("${rootProject.name}-Bukkit-${project.version}.${archiveExtension.getOrElse("jar")}")
|
||||
dependencies {
|
||||
// In tandem with not bundling log4j, we shouldn't relocate base package here.
|
||||
// relocate("org.apache.logging", "com.sk89q.worldedit.log4j")
|
||||
@ -163,21 +165,24 @@ tasks.named<ShadowJar>("shadowJar") {
|
||||
relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") {
|
||||
include(dependency("it.unimi.dsi:fastutil"))
|
||||
}
|
||||
relocate("org.incendo.serverlib", "com.boydti.fawe.serverlib") {
|
||||
include(dependency("org.incendo.serverlib:ServerLib:2.2.0"))
|
||||
relocate("org.incendo.serverlib", "com.fastasyncworldedit.serverlib") {
|
||||
include(dependency("org.incendo.serverlib:ServerLib:2.2.1"))
|
||||
}
|
||||
relocate("com.intellectualsites.paster", "com.boydti.fawe.paster") {
|
||||
relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") {
|
||||
include(dependency("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT"))
|
||||
}
|
||||
relocate("com.github.luben", "com.boydti.fawe.zstd") {
|
||||
relocate("com.github.luben", "com.fastasyncworldedit.core.zstd") {
|
||||
include(dependency("com.github.luben:zstd-jni:1.5.0-2"))
|
||||
}
|
||||
relocate("net.jpountz", "com.boydti.fawe.jpountz") {
|
||||
relocate("net.jpountz", "com.fastasyncworldedit.core.jpountz") {
|
||||
include(dependency("net.jpountz:lz4-java-stream:1.0.0"))
|
||||
}
|
||||
relocate("org.lz4", "com.boydti.fawe.lz4") {
|
||||
relocate("org.lz4", "com.fastasyncworldedit.core.lz4") {
|
||||
include(dependency("org.lz4:lz4-java:1.8.0"))
|
||||
}
|
||||
relocate("net.kyori", "com.fastasyncworldedit.core.adventure") {
|
||||
include(dependency("net.kyori:adventure-nbt:4.7.0"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NMSRelighterFactory implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
return new NMSRelighter(queue,
|
||||
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockAccessAir;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.ITileEntity;
|
||||
import net.minecraft.server.v1_15_R1.Material;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_15_2 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
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 BlockMaterial_1_15_2(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_15_2(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
this.isTranslucent = !(boolean) ReflectionUtil.getField(Block.class, block, "v");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return block.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.m();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.h();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
return !material.isAlwaysDestroyable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.i().rgb;
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.DataBits;
|
||||
import net.minecraft.server.v1_15_R1.DataPalette;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineStorage;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private final static MethodHandle methodGetVisibleChunk;
|
||||
|
||||
public static final MethodHandle methodSetLightNibbleArray;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
|
||||
fieldSize.setAccessible(true);
|
||||
fieldBits = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldBits.setAccessible(true);
|
||||
fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldFluidCount = ChunkSection.class.getDeclaredField("e");
|
||||
fieldFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("g");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Method declaredSetLightNibbleArray = LightEngineStorage.class.getDeclaredMethod("a", long.class, NibbleArray.class);
|
||||
declaredSetLightNibbleArray.setAccessible(true);
|
||||
methodSetLightNibbleArray = MethodHandles.lookup().unreflect(declaredSetLightNibbleArray);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0) {
|
||||
throw new Error("data type scale not a power of two");
|
||||
}
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
|
||||
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
|
||||
if (layer >= 0 && layer < sections.length) {
|
||||
return UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkIfLoaded(chunkX, chunkZ);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// BlockStates
|
||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
|
||||
} else {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
|
||||
}
|
||||
|
||||
final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6;
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArray bitArray = new BitArray(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// set palette & data bits
|
||||
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
||||
// private DataPalette<T> h;
|
||||
// protected DataBits a;
|
||||
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
|
||||
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
|
||||
final DataPalette<IBlockData> palette;
|
||||
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_15_2) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,916 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArray;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.DataBits;
|
||||
import net.minecraft.server.v1_15_R1.DataPalette;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_15_R1.HeightMap;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngine;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_15_2_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_15_2(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_15_2(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArray bitArray = new BitArray(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's not got any emitted light. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 0);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArray bitArray = new BitArray(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_15_2 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_15_R1.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_15_2.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_15_2.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_15_2.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_15_2.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_15_2.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_15_2.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_15_2.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = nativeTag.getValue();
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
LOGGER.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
|
||||
entity.f(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_15_2.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_15_2.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_15_2.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_15_R2 adapter = ((FAWE_Spigot_v1_15_R2) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_15_2.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15_2.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = bits.c();
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArray(bitsPerEntry, 4096, blockStates).toRaw(data);
|
||||
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_15_R2 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15_2.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
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 BukkitGetBlocks_1_15_2_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_15_2_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_15_2.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@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(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
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 getEmmittedLight(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;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
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 net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_15_R1.EnumDirection;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
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;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_15_R2 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_15_2(FAWE_Spigot_v1_15_R2 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// 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 World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(com.sk89q.worldedit.world.block.BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
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(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load((NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY);
|
||||
newState.b(world, pos, NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_15_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_15_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_15_2 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_15_2() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTNumber;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagList;
|
||||
|
||||
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 LazyCompoundTag_1_15_2 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_15_2(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_15_2(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_15_2((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
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 nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R1.BlockBase;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R1.Material;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_1 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
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 BlockMaterial_1_16_1(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_1(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.DataBits;
|
||||
import net.minecraft.server.v1_16_R1.DataPalette;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_1 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private final static MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
|
||||
fieldSize.setAccessible(true);
|
||||
fieldBits = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldBits.setAccessible(true);
|
||||
fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.setAccessible(true);
|
||||
|
||||
fieldFluidCount = ChunkSection.class.getDeclaredField("e");
|
||||
fieldFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("g");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0) {
|
||||
throw new Error("data type scale not a power of two");
|
||||
}
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
|
||||
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
|
||||
if (layer >= 0 && layer < sections.length) {
|
||||
return UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535, true);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// BlockStates
|
||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
|
||||
} else {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
|
||||
}
|
||||
|
||||
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// set palette & data bits
|
||||
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
||||
// private DataPalette<T> h;
|
||||
// protected DataBits a;
|
||||
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
|
||||
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
|
||||
final DataPalette<IBlockData> palette;
|
||||
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,917 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.DataBits;
|
||||
import net.minecraft.server.v1_16_R1.DataPalette;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R1.HeightMap;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.LightEngine;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_1_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_1(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_1(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_1 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R1.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_1.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_1.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_1.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + "," +
|
||||
chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_1.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_1.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_1
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_1
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_1.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_1.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_1.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = nativeTag.getValue();
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
LOGGER.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_1.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_1.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_1.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R1 adapter = ((FAWE_Spigot_v1_16_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_1.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_1.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data);
|
||||
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R1 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
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 BukkitGetBlocks_1_16_1_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_1_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_16_1.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@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(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
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 getEmmittedLight(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;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
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.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R1.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
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;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_16_R1 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R1 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R1(FAWE_Spigot_v1_16_R1 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// 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 World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
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(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_1.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_1.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_1 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_1() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagList;
|
||||
|
||||
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 LazyCompoundTag_1_16_1 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_1(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_1(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_1((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
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 nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R2.BlockBase;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R2.Material;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_2 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
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 BlockMaterial_1_16_2(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_2(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.DataBits;
|
||||
import net.minecraft.server.v1_16_R2.DataPalette;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R2.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_2 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
|
||||
fieldSize.setAccessible(true);
|
||||
fieldBits = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldBits.setAccessible(true);
|
||||
fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.setAccessible(true);
|
||||
|
||||
fieldFluidCount = ChunkSection.class.getDeclaredField("e");
|
||||
fieldFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("h");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0) {
|
||||
throw new Error("data type scale not a power of two");
|
||||
}
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
|
||||
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
|
||||
if (layer >= 0 && layer < sections.length) {
|
||||
return UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int chunkX, final int chunkZ) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(chunkX, chunkZ));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// BlockStates
|
||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
|
||||
} else {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
|
||||
}
|
||||
|
||||
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// set palette & data bits
|
||||
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
||||
// private DataPalette<T> h;
|
||||
// protected DataBits a;
|
||||
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
|
||||
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
|
||||
final DataPalette<IBlockData> palette;
|
||||
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_2) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,920 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.DataBits;
|
||||
import net.minecraft.server.v1_16_R2.DataPalette;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R2.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R2.HeightMap;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.LightEngine;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R2.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R2.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_2_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_2(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_2(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_2 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R2.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_2.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_2.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_2.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_2.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_2.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_2
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_2
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(nmsWorld.r().b(IRegistry.ay), craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_2.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_2.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_2.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = nativeTag.getValue();
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
LOGGER.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_2.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_2.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_2.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R2 adapter = ((FAWE_Spigot_v1_16_R2) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_2.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_2.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_2.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data);
|
||||
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R2 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_2.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
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 BukkitGetBlocks_1_16_2_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_2_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_2.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@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(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
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 getEmmittedLight(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;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
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.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R2.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
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;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_16_R2 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R2 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R2(FAWE_Spigot_v1_16_R2 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// 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 World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
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(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_2 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_2() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagList;
|
||||
|
||||
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 LazyCompoundTag_1_16_2 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_2(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_2(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_2((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
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 nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R3.BlockBase;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R3.Material;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_5 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
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 BlockMaterial_1_16_5(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_5(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.DataBits;
|
||||
import net.minecraft.server.v1_16_R3.DataPalette;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R3.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_5 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
|
||||
fieldSize.setAccessible(true);
|
||||
fieldBits = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldBits.setAccessible(true);
|
||||
fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
|
||||
fieldPalette.setAccessible(true);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.setAccessible(true);
|
||||
|
||||
fieldFluidCount = ChunkSection.class.getDeclaredField("e");
|
||||
fieldFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("h");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0) {
|
||||
throw new Error("data type scale not a power of two");
|
||||
}
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
rethrow.printStackTrace();
|
||||
throw new RuntimeException(rethrow);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
|
||||
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
|
||||
if (layer >= 0 && layer < sections.length) {
|
||||
return UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int chunkX, final int chunkZ) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(chunkX, chunkZ));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// BlockStates
|
||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
|
||||
} else {
|
||||
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
|
||||
}
|
||||
|
||||
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// set palette & data bits
|
||||
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
||||
// private DataPalette<T> h;
|
||||
// protected DataBits a;
|
||||
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
|
||||
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
|
||||
final DataPalette<IBlockData> palette;
|
||||
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_5) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,920 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.DataBits;
|
||||
import net.minecraft.server.v1_16_R3.DataPalette;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R3.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R3.HeightMap;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.LightEngine;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R3.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R3.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitGetBlocks_1_16_5 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_5_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_5(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_5(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_5 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R3.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_5.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_5_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
final BlockPosition pos = entry.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int layer = ly >> 4;
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_5.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_5.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_5.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_5.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_5
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_5
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(nmsWorld.r().b(IRegistry.ay), craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_5.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_5.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_5.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = nativeTag.getValue();
|
||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||
if (idTag == null || posTag == null || rotTag == null) {
|
||||
LOGGER.debug("Unknown entity tag: " + nativeTag);
|
||||
continue;
|
||||
}
|
||||
final double x = posTag.getDouble(0);
|
||||
final double y = posTag.getDouble(1);
|
||||
final double z = posTag.getDouble(2);
|
||||
final float yaw = rotTag.getFloat(0);
|
||||
final float pitch = rotTag.getFloat(1);
|
||||
final String id = idTag.getValue();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_5.this.update(layer, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_5.sendChunk(world, chunkX, chunkZ, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_5.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R3 adapter = ((FAWE_Spigot_v1_16_R3) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_5.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_5.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_5.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data);
|
||||
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R3 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_5.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
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 BukkitGetBlocks_1_16_5_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_5_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(biomeStorage.registry, BukkitAdapter_1_16_5.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@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(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
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 getEmmittedLight(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;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
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.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R3.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.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 FAWEWorldNativeAccess_1_16_R3 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R3 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R3(FAWE_Spigot_v1_16_R3 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// 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 World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
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(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_5.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_5.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_5 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_5() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NullRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TuinityRelighterFactory_1_16_5 implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull 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 TuinityRelighter_1_16_5(((CraftWorld) w).getHandle(), queue);
|
||||
}
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.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.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R3.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R3.MCUtil;
|
||||
import net.minecraft.server.v1_16_R3.TicketType;
|
||||
import net.minecraft.server.v1_16_R3.Unit;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
public class TuinityRelighter_1_16_5 implements Relighter {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final MethodHandle RELIGHT;
|
||||
|
||||
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.a("fawe_ticket", (a, b) -> 0);
|
||||
private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT);
|
||||
|
||||
private final WorldServer world;
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final Long2ObjectLinkedOpenHashMap<LongSet> regions = new Long2ObjectLinkedOpenHashMap<>();
|
||||
|
||||
private final ReentrantLock areaLock = new ReentrantLock();
|
||||
private final NMSRelighter delegate;
|
||||
|
||||
static {
|
||||
MethodHandle tmp = null;
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
tmp = lookup.findVirtual(LightEngineThreaded.class,
|
||||
"relight",
|
||||
MethodType.methodType(
|
||||
int.class, // return type
|
||||
// params
|
||||
Set.class,
|
||||
Consumer.class,
|
||||
IntConsumer.class
|
||||
)
|
||||
);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
LOGGER.error("Failed to locate relight method in LightEngineThreaded on Tuinity. " +
|
||||
"Is everything up to date?", e);
|
||||
}
|
||||
RELIGHT = tmp;
|
||||
}
|
||||
|
||||
public TuinityRelighter_1_16_5(WorldServer world, IQueueExtent<IQueueChunk> queue) {
|
||||
this.world = world;
|
||||
this.delegate = new NMSRelighter(queue, false);
|
||||
}
|
||||
|
||||
@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(ChunkCoordIntPair.pair(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 ChunkCoordIntPairs
|
||||
Set<ChunkCoordIntPair> coords = new HashSet<>();
|
||||
LongIterator iterator = chunks.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
coords.add(new ChunkCoordIntPair(iterator.nextLong()));
|
||||
}
|
||||
TaskManager.IMP.task(() -> {
|
||||
// trigger chunk load and apply ticket on main thread
|
||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||
for (ChunkCoordIntPair pos : coords) {
|
||||
futures.add(world.getWorld().getChunkAtAsync(pos.x, pos.z)
|
||||
.thenAccept(c -> world.getChunkProvider().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 " + i + " chunks instead of " + coords.size());
|
||||
}
|
||||
// post process chunks on main thread
|
||||
TaskManager.IMP.task(() -> postProcessChunks(coords));
|
||||
// call callback on our own threads
|
||||
TaskManager.IMP.async(andThen);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private void invokeRelight(Set<ChunkCoordIntPair> coords,
|
||||
Consumer<ChunkCoordIntPair> chunkCallback,
|
||||
IntConsumer processCallback) {
|
||||
try {
|
||||
int unused = (int) RELIGHT.invokeExact(world.getChunkProvider().getLightEngine(),
|
||||
coords,
|
||||
chunkCallback, // callback per chunk
|
||||
processCallback // callback for all chunks
|
||||
);
|
||||
} catch (Throwable throwable) {
|
||||
LOGGER.error("Error occurred on relighting", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the server to unload the chunks again.
|
||||
* Also, if chunk packets are sent delayed, we need to do that here
|
||||
*/
|
||||
private void postProcessChunks(Set<ChunkCoordIntPair> coords) {
|
||||
boolean delay = Settings.IMP.LIGHTING.DELAY_PACKET_SENDING;
|
||||
for (ChunkCoordIntPair pos : coords) {
|
||||
int x = pos.x;
|
||||
int z = pos.z;
|
||||
if (delay) { // we still need to send the block changes of that chunk
|
||||
BukkitAdapter_1_16_5.sendChunk(world, x, z, false);
|
||||
}
|
||||
world.getChunkProvider().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,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagList;
|
||||
|
||||
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 LazyCompoundTag_1_16_5 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_5(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_5(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_5((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
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 nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.plotsquared.core.queue.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
// TODO FIXME
|
||||
public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean setbiome = false;
|
||||
|
||||
public FaweLocalBlockQueue(String worldName) {
|
||||
super(worldName);
|
||||
this.world = FaweAPI.getWorld(worldName);
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
if (!instance.isEmpty()) {
|
||||
instance.flush();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().startSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().endSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optimize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModified() {
|
||||
return instance.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
setbiome = true;
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome() {
|
||||
return setbiome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return world.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
instance.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(int x, int z) {
|
||||
world.refreshChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixChunkLighting(int x, int z) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
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.Captions;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.WorldUtil;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage("Already running!");
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage("First make a backup of your world called <world-copy> then stand in the middle of an empty plot");
|
||||
plotPlayer.sendMessage("use /plot trimall <world> <boolean-delete-unowned>");
|
||||
return false;
|
||||
}
|
||||
if (!WorldUtil.IMP.isWorld(strings[0])) {
|
||||
Captions.NOT_VALID_PLOT_WORLD.send(plotPlayer, strings[0]);
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
// PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
// Location loc = plotPlayer.getLocation();
|
||||
// trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
// trim.run();
|
||||
// plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.plotsquared.core.command.Command;
|
||||
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.Captions;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.MainUtil;
|
||||
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;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>"
|
||||
)
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer<?> player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions
|
||||
.hasPermission(player, "plots.admin.command.generatebiome"), Captions.NO_PLOT_PERMS);
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan
|
||||
.join(BiomeType.REGISTRY.values(), Captions.BLOCK_LIST_SEPARATOR.getTranslated());
|
||||
Captions.NEED_BIOME.send(player);
|
||||
MainUtil.sendMessage(player, Captions.SUBCOMMAND_SET_OPTIONS_HEADER.toString() + biomes);
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session = new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().getWorldName())))
|
||||
.autoQueue(false)
|
||||
.checkMemory(false)
|
||||
.allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID())))
|
||||
.limitUnlimited()
|
||||
.build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
|
@ -1,31 +1,32 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.FAWEPlatformAdapterImpl;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.AsyncPreloader;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.Preloader;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.bukkit.listener.BrushListener;
|
||||
import com.boydti.fawe.bukkit.listener.ChunkListener9;
|
||||
import com.boydti.fawe.bukkit.listener.RenderListener;
|
||||
import com.boydti.fawe.bukkit.regions.GriefPreventionFeature;
|
||||
import com.boydti.fawe.bukkit.regions.GriefDefenderFeature;
|
||||
import com.boydti.fawe.bukkit.regions.ResidenceFeature;
|
||||
import com.boydti.fawe.bukkit.regions.TownyFeature;
|
||||
import com.boydti.fawe.bukkit.regions.Worldguard;
|
||||
import com.boydti.fawe.bukkit.util.BukkitTaskManager;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.boydti.fawe.bukkit.util.MinecraftVersion;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.ThirdPartyManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.IFawe;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.AsyncPreloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.Preloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||
import com.fastasyncworldedit.bukkit.listener.BrushListener;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener9;
|
||||
import com.fastasyncworldedit.bukkit.listener.RenderListener;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefPreventionFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefDefenderFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.ResidenceFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.TownyFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.Worldguard;
|
||||
import com.fastasyncworldedit.bukkit.util.BukkitTaskManager;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
||||
import com.fastasyncworldedit.bukkit.util.image.BukkitImageViewer;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.util.ThirdPartyManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -291,12 +292,13 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return;
|
||||
}
|
||||
if (plotSquared.getClass().getPackage().toString().contains("intellectualsites")) {
|
||||
WEManager.IMP.managers
|
||||
.add(new com.boydti.fawe.bukkit.regions.plotsquaredv4.PlotSquaredFeature());
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquaredv4.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else if (PlotSquared.get().getVersion().version[0] == 6){
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else {
|
||||
WEManager.IMP.managers
|
||||
.add(new com.boydti.fawe.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
|
||||
}
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
public interface BukkitGetBlocks {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import co.aikar.timings.Timings;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.listener.ChunkListener;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spigotmc.AsyncCatcher;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.destroystokyo.paper.util.ReentrantLockWithGetOwner;
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class DelegateSemaphore extends Semaphore {
|
||||
private final Semaphore delegate;
|
||||
|
||||
public DelegateSemaphore(int permits, Semaphore delegate) {
|
||||
super(permits);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
// this is bad
|
||||
@Override
|
||||
public synchronized boolean tryAcquire() {
|
||||
try {
|
||||
this.delegate.acquire();
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void acquire() throws InterruptedException {
|
||||
this.delegate.acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
this.delegate.release();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
@ -21,6 +22,7 @@ import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
@ -39,11 +41,6 @@ import java.util.OptionalInt;
|
||||
public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
BukkitImplAdapter<T> getParent();
|
||||
|
||||
@Override
|
||||
default int getDataVersion() {
|
||||
return getParent().getDataVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default DataFixer getDataFixer() {
|
||||
@ -83,7 +80,7 @@ public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) {
|
||||
getParent().sendFakeNBT(player, pos, nbtData);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -18,7 +18,7 @@ public abstract class MapChunkUtil<T> {
|
||||
protected Field fieldBlockEntities;
|
||||
protected Field fieldFull;
|
||||
|
||||
public abstract T createPacket();
|
||||
protected abstract T createPacket();
|
||||
|
||||
public T create(BukkitImplAdapter adapter, ChunkPacket packet) {
|
||||
try {
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.FAWEPlatformAdapterImpl;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
@ -0,0 +1,19 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.NMSRelighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.Relighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NMSRelighterFactory implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
return new NMSRelighter(queue,
|
||||
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.fastasyncworldedit.core.beta.IChunkCache;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
@ -1,5 +1,6 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.griefdefender.api.claim.Claim;
|
||||
import com.griefdefender.api.GriefDefender;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import me.ryanhamshire.GriefPrevention.GriefPrevention;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.object.brush.MovableTool;
|
||||
import com.boydti.fawe.object.brush.ResettableTool;
|
||||
import com.boydti.fawe.object.brush.scroll.ScrollTool;
|
||||
import com.fastasyncworldedit.core.object.brush.MovableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.ResettableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.scroll.ScrollTool;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
@ -1,11 +1,11 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
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.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.preloader;
|
||||
package com.fastasyncworldedit.bukkit.preloader;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.regions.Region;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
|
||||
public abstract class BukkitMaskManager extends FaweMaskManager {
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.GriefDefenderFilter;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefDefenderFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.griefdefender.api.GriefDefender;
|
||||
import com.griefdefender.api.claim.Claim;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.GriefPreventionFilter;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefPreventionFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
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.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
||||
import com.palmergames.bukkit.towny.object.PlayerCache;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.WorldGuardFilter;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.WorldGuardFilter;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.generator.HybridPlotManager;
|
||||
import com.plotsquared.core.generator.HybridPlotWorld;
|
||||
@ -13,7 +13,6 @@ import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.PlotAreaTerrainType;
|
||||
import com.plotsquared.core.plot.PlotAreaType;
|
||||
import com.plotsquared.core.plot.PlotManager;
|
||||
import com.plotsquared.core.util.RegionManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -33,41 +32,32 @@ import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
|
||||
public class FaweRegionManager extends RegionManager {
|
||||
public class FaweDelegateRegionManager {
|
||||
|
||||
private final RegionManager parent;
|
||||
|
||||
public FaweRegionManager(RegionManager parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] countEntities(Plot plot) {
|
||||
return parent.countEntities(plot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllEntities(Location pos1, Location pos2) {
|
||||
parent.clearAllEntities(pos1, pos2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setCuboids(final PlotArea area, final Set<CuboidRegion> regions, final Pattern blocks, final int minY, final int maxY) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CUBOIDS) {
|
||||
return parent.setCuboids(area, regions, blocks, minY, maxY);
|
||||
}
|
||||
public boolean setCuboids(final @NonNull PlotArea area,
|
||||
final @NonNull Set<CuboidRegion> regions,
|
||||
final @NonNull Pattern blocks,
|
||||
int minY,
|
||||
int maxY,
|
||||
Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World world = BukkitAdapter.adapt(getWorld(area.getWorldName()));
|
||||
EditSession session = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession session =
|
||||
new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull()
|
||||
.autoQueue(false).build();
|
||||
for (CuboidRegion region : regions) {
|
||||
region.setPos1(region.getPos1().withY(minY));
|
||||
region.setPos2(region.getPos2().withY(maxY));
|
||||
@ -77,32 +67,28 @@ public class FaweRegionManager extends RegionManager {
|
||||
session.flushQueue();
|
||||
for (CuboidRegion region : regions) {
|
||||
FaweAPI.fixLighting(world, region, null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyClear(PlotManager manager) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CLEAR || !(manager instanceof HybridPlotManager)) {
|
||||
return false;
|
||||
}
|
||||
final HybridPlotWorld hpw = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
return hpw.getType() != PlotAreaType.AUGMENTED || hpw.getTerrain() == PlotAreaTerrainType.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClear(final Plot plot, final Runnable whenDone, final PlotManager manager) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CLEAR || !(manager instanceof HybridPlotManager)) {
|
||||
return false;
|
||||
}
|
||||
public boolean handleClear(@NotNull Plot plot,
|
||||
@Nullable Runnable whenDone,
|
||||
@NotNull PlotManager manager) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
final HybridPlotWorld hybridPlotWorld = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
World world = BukkitAdapter.adapt(getWorld(hybridPlotWorld.getWorldName()));
|
||||
EditSession editSession = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
@ -157,56 +143,58 @@ public class FaweRegionManager extends RegionManager {
|
||||
// Be verbose in editsession flushing
|
||||
editSession.flushQueue();
|
||||
FaweAPI.fixLighting(world, new CuboidRegion(plot.getBottomAbs().getBlockVector3(), plot.getTopAbs().getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(final Location pos1, final Location pos2, final Location pos3, final Location pos4, final Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
parent.swap(pos1, pos2, pos3, pos4, whenDone);
|
||||
}
|
||||
public void swap(Location pos1,
|
||||
Location pos2,
|
||||
Location swapPos,
|
||||
final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
//todo because of the following code this should proably be in the Bukkit module
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName()));
|
||||
WorldEdit.getInstance().getEditSessionFactory().getEditSession(pos1World, -1);
|
||||
EditSession sessionA = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession sessionB = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion regionA = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
CuboidRegion regionB = new CuboidRegion(BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()), BlockVector3.at(pos4.getX(), pos4.getY(), pos4.getZ()));
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint());
|
||||
CuboidRegion regionA = new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3());
|
||||
CuboidRegion regionB = new CuboidRegion(swapPos.getBlockVector3(), swapPos.getBlockVector3().add(pos2.getBlockVector3()).subtract(pos1.getBlockVector3()));
|
||||
regionA.setWorld(pos1World);
|
||||
regionB.setWorld(pos3World);
|
||||
Clipboard clipA = Clipboard.create(regionA, UUID.randomUUID());
|
||||
Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID());
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, clipA, clipA.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, clipB, clipB.getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copyA);
|
||||
Operations.completeLegacy(copyB);
|
||||
clipA.paste(sessionB, swapPos.getBlockVector3(), true);
|
||||
clipB.paste(sessionA, pos1.getBlockVector3(), true);
|
||||
sessionA.flushQueue();
|
||||
sessionB.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos3.getBlockVector3(), pos4.getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(swapPos.getBlockVector3(),
|
||||
BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), 0, swapPos.getZ() + pos2.getZ() - pos1.getZ())), null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, String world, Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.SET_BIOME) {
|
||||
parent.setBiome(region, extendBiome, biome, world, whenDone);
|
||||
}
|
||||
region.expand(BlockVector3.at(extendBiome, 0, extendBiome));
|
||||
region.expand(BlockVector3.at(-extendBiome, 0, -extendBiome));
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
EditSession editSession = new EditSessionBuilder(BukkitAdapter.adapt(getWorld(world))).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
FlatRegionFunction replace = new BiomeReplace(editSession, biome);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(region, replace);
|
||||
@ -221,15 +209,14 @@ public class FaweRegionManager extends RegionManager {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
return parent.copyRegion(pos1, pos2, pos3, whenDone);
|
||||
}
|
||||
public boolean copyRegion(final @NonNull Location pos1,
|
||||
final @NonNull Location pos2,
|
||||
final @NonNull Location pos3,
|
||||
final @NonNull Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorldName()));
|
||||
EditSession from = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession to = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
@ -239,7 +226,7 @@ public class FaweRegionManager extends RegionManager {
|
||||
to.flushQueue();
|
||||
FaweAPI.fixLighting(pos1World,
|
||||
new CuboidRegion(pos3.getBlockVector3(), pos3.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3()))),
|
||||
null, RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -249,11 +236,10 @@ public class FaweRegionManager extends RegionManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
try (EditSession editSession = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
editSession.regenerate(region);
|
@ -1,18 +1,20 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.generator.ClassicPlotWorld;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.schematic.Schematic;
|
||||
import com.plotsquared.core.queue.LocalBlockQueue;
|
||||
import com.plotsquared.core.util.MainUtil;
|
||||
import com.plotsquared.core.util.FileUtils;
|
||||
import com.plotsquared.core.util.SchematicHandler;
|
||||
import com.plotsquared.core.util.task.RunnableVal;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompressedCompoundTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
@ -20,18 +22,17 @@ import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
@ -45,64 +46,109 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
public class FaweDelegateSchematicHandler {
|
||||
|
||||
public class FaweSchematicHandler extends SchematicHandler {
|
||||
@Override
|
||||
public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) {
|
||||
if (queue instanceof FaweLocalBlockQueue) {
|
||||
queue.setTile(x, y, z, compoundTag);
|
||||
return true;
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final AtomicBoolean exportingAll = new AtomicBoolean();
|
||||
|
||||
public void paste(final Schematic schematic,
|
||||
final Plot plot,
|
||||
final int xOffset,
|
||||
final int yOffset,
|
||||
final int zOffset,
|
||||
final boolean autoHeight,
|
||||
final RunnableVal<Boolean> whenDone) {
|
||||
Runnable r = () -> {
|
||||
if (whenDone != null) {
|
||||
whenDone.value = false;
|
||||
}
|
||||
if (schematic == null) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
BlockVector3 dimension = schematic.getClipboard().getDimensions();
|
||||
final int WIDTH = dimension.getX();
|
||||
final int LENGTH = dimension.getZ();
|
||||
final int HEIGHT = dimension.getY();
|
||||
// Validate dimensions
|
||||
CuboidRegion region = plot.getLargestRegion();
|
||||
if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
|
||||
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT
|
||||
> 256)) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
// Calculate the optimal height to paste the schematic at
|
||||
final int y_offset_actual;
|
||||
if (autoHeight) {
|
||||
if (HEIGHT >= 256) {
|
||||
y_offset_actual = yOffset;
|
||||
} else {
|
||||
PlotArea pw = plot.getArea();
|
||||
if (pw instanceof ClassicPlotWorld) {
|
||||
y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
|
||||
} else {
|
||||
y_offset_actual = yOffset + 1 + PlotSquared.platform().worldUtil()
|
||||
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
|
||||
region.getMinimumPoint().getZ() + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
y_offset_actual = yOffset;
|
||||
}
|
||||
|
||||
final BlockVector3 to = BlockVector3
|
||||
.at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
|
||||
|
||||
try (EditSession editSession = new EditSessionBuilder(FaweAPI.getWorld(plot.getWorldName())).checkMemory(false)
|
||||
.fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
final Clipboard clipboard = schematic.getClipboard();
|
||||
clipboard.paste(editSession, to, true, false, true);
|
||||
if (whenDone != null) {
|
||||
whenDone.value = true;
|
||||
TaskManager.runTask(whenDone);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
com.fastasyncworldedit.core.util.TaskManager.IMP.async(r);
|
||||
} else {
|
||||
r.run();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCompoundTag(final String world, final Set<CuboidRegion> regions, final RunnableVal<CompoundTag> whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
Location[] corners = MainUtil.getCorners(world, regions);
|
||||
Location pos1 = corners[0];
|
||||
Location pos2 = corners[1];
|
||||
World adaptedWorld = BukkitAdapter.adapt(getWorld(world));
|
||||
final CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
final EditSession editSession = new EditSessionBuilder(adaptedWorld).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
|
||||
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
|
||||
|
||||
Clipboard holder = new BlockArrayClipboard(region, clipboard);
|
||||
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
|
||||
whenDone.run(tag);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(CompoundTag tag, String path) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File tmp = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), path);
|
||||
File tmp = FileUtils.getFile(PlotSquared.platform().getDirectory(), path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
if (tag instanceof CompressedCompoundTag) {
|
||||
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
|
||||
if (cTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = (Clipboard) cTag.getSource();
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(
|
||||
new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
new FastSchematicWriter(output).write(clipboard);
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
|
||||
IOUtil.copy(is, stream);
|
||||
IOUtil.copy(is, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
|
||||
}
|
||||
@ -116,15 +162,14 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
com.plotsquared.core.util.task.TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
MainUtil.upload(uuid, file, "schem", new RunnableVal<OutputStream>() {
|
||||
SchematicHandler.upload(uuid, file, "schem", new RunnableVal<>() {
|
||||
@Override
|
||||
public void run(OutputStream output) {
|
||||
if (weTag instanceof CompressedSchematicTag) {
|
||||
@ -145,7 +190,6 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
}, whenDone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Schematic getSchematic(@NotNull InputStream is) {
|
||||
try {
|
||||
FastSchematicReader schematicReader = new FastSchematicReader(
|
||||
@ -174,8 +218,8 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
return new Schematic(clip);
|
||||
} catch (IOException e3) {
|
||||
e.printStackTrace();
|
||||
PlotSquared.debug(
|
||||
is.toString() + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
|
||||
LOGGER.warn(
|
||||
is + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.plotsquared.core.queue.LightingMode;
|
||||
import com.plotsquared.core.queue.QueueCoordinator;
|
||||
import com.plotsquared.core.queue.subscriber.ProgressSubscriber;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FaweQueueCoordinator extends QueueCoordinator {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean setbiome = false;
|
||||
|
||||
public FaweQueueCoordinator(World world) {
|
||||
super(world);
|
||||
this.world = world;
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
setbiome = true;
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, @NotNull BiomeType biome) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingBiomes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setEntity(@NotNull Entity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<BlockVector2> getReadChunks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunks(@NotNull Set<BlockVector2> readChunks) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunk(@NotNull BlockVector2 chunk) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnloadAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnloadAfter(boolean unloadAfter) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CuboidRegion getRegenRegion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegenRegion(@NotNull CuboidRegion regenRegion) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable getCompleteTask() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompleteTask(@Nullable Runnable whenDone) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Consumer<BlockVector2> getChunkConsumer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkConsumer(@NotNull Consumer<BlockVector2> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProgressSubscriber(@NotNull ProgressSubscriber progressSubscriber) {
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightingMode getLightingMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingMode(@Nullable LightingMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingTiles() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
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;
|
||||
|
||||
@CommandDeclaration(command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("error.task_in_process"));
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage(StaticCaption
|
||||
.of("First make a backup of your world called <world-copy> then stand in the middle of an empty plot"));
|
||||
plotPlayer.sendMessage(StaticCaption.of("use /plot trimall <world> <boolean-delete-unowned>"));
|
||||
return false;
|
||||
}
|
||||
if (!PlotSquared.platform().worldUtil().isWorld(strings[0])) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("errors.not_valid_plot_world"), Templates.of("value", strings[0]));
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(() -> {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
//PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
//Location loc = plotPlayer.getLocation();
|
||||
//trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
//trim.run();
|
||||
//plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
|
||||
import com.plotsquared.core.command.CommandCategory;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
@ -0,0 +1,108 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.command.Command;
|
||||
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;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandDeclaration(command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.PLAYER,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>")
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer<?> player,
|
||||
String[] args,
|
||||
RunnableVal3<Command, Runnable, Runnable> confirm,
|
||||
RunnableVal2<Command, CommandResult> whenDone) 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"),
|
||||
TranslatableCaption.of("permission.no_plot_perms"));
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, TranslatableCaption.of("commandconfig.command_syntax"),
|
||||
Templates.of("value", getUsage()));
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry =
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries()
|
||||
.getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan.join(BiomeType.REGISTRY.values(),
|
||||
TranslatableCaption.of("blocklist.block_list_separator").getComponent(player));
|
||||
player.sendMessage(TranslatableCaption.of("biome.need_biome"));
|
||||
player.sendMessage(TranslatableCaption.of("commandconfig.subcommand_set_options_header"),
|
||||
Templates.of("values", biomes));
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session =
|
||||
new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().getWorldName())))
|
||||
.autoQueue(false).checkMemory(false).allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID()))).limitUnlimited().build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) {
|
||||
return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, args[0])
|
||||
.map(value -> value.toLowerCase(Locale.ENGLISH).replace("minecraft:", ""))
|
||||
.filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH)))
|
||||
.map(value -> new Command(null, false, value, "", RequiredType.PLAYER, null) {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
@ -14,9 +14,8 @@ import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.NoWorldeditFlag;
|
||||
import com.plotsquared.core.util.RegionManager;
|
||||
import com.plotsquared.core.util.SchematicHandler;
|
||||
import com.plotsquared.core.util.WEManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -39,15 +38,8 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (com.boydti.fawe.config.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_HOOK) {
|
||||
if (Settings.FAWE_Components.FAWE_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
try {
|
||||
setupBlockQueue();
|
||||
setupSchematicHandler();
|
||||
setupRegionManager();
|
||||
} catch (Throwable ignored) {
|
||||
LOGGER.debug("Please update PlotSquared: https://www.spigotmc.org/resources/77506/");
|
||||
}
|
||||
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
|
||||
new FaweTrim();
|
||||
}
|
||||
@ -71,38 +63,20 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
return UUIDHandler.getName(uuid);
|
||||
}
|
||||
|
||||
private void setupBlockQueue() throws RuntimeException {
|
||||
// If it's going to fail, throw an error now rather than later
|
||||
//QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
|
||||
//GlobalBlockQueue.IMP.setProvider(provider);
|
||||
//HybridPlotManager.REGENERATIVE_CLEAR = false;
|
||||
//log.debug(" - QueueProvider: " + FaweLocalBlockQueue.class);
|
||||
//log.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR);
|
||||
}
|
||||
|
||||
private void setupRegionManager() throws RuntimeException {
|
||||
RegionManager.manager = new FaweRegionManager(RegionManager.manager);
|
||||
LOGGER.debug(" - RegionManager: " + RegionManager.manager);
|
||||
}
|
||||
|
||||
private void setupSchematicHandler() throws RuntimeException {
|
||||
SchematicHandler.manager = new FaweSchematicHandler();
|
||||
LOGGER.debug(" - SchematicHandler: " + SchematicHandler.manager);
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type) {
|
||||
if (plot == null) {
|
||||
return false;
|
||||
}
|
||||
UUID uid = player.getUniqueId();
|
||||
return !plot.getFlag(NoWorldeditFlag.class) && (plot.isOwner(uid) || type == MaskType.MEMBER && (plot.getTrusted().contains(uid) || plot
|
||||
.getTrusted().contains(DBFunc.EVERYONE) || (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player
|
||||
.hasPermission("fawe.plotsquared.member")) || player.hasPermission("fawe.plotsquared.admin"));
|
||||
return !plot.getFlag(NoWorldeditFlag.class) && (plot.isOwner(uid) || type == MaskType.MEMBER && (
|
||||
plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)
|
||||
|| (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player
|
||||
.hasPermission("fawe.plotsquared.member")) || player.hasPermission("fawe.plotsquared.admin"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type) {
|
||||
final PlotPlayer pp = PlotPlayer.wrap(player.getUniqueId());
|
||||
final PlotPlayer<org.bukkit.entity.Player> pp = PlotPlayer.from(BukkitAdapter.adapt(player));
|
||||
if (pp == null) {
|
||||
return null;
|
||||
}
|
||||
@ -115,7 +89,8 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
regions = WEManager.getMask(pp);
|
||||
if (regions.size() == 1) {
|
||||
CuboidRegion region = regions.iterator().next();
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE && region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE
|
||||
&& region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
regions.clear();
|
||||
}
|
||||
}
|
||||
@ -159,7 +134,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
PlotArea area = PlotSquared.get().getPlotArea(world, null);
|
||||
PlotArea area = PlotSquared.get().getPlotAreaManager().getPlotArea(world, null);
|
||||
if (area != null) {
|
||||
return new PlotRegionFilter(area);
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
@ -1,12 +1,12 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.clipboard.ReadOnlyClipboard;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.Command;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Settings;
|
||||
@ -40,7 +40,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (com.boydti.fawe.config.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_HOOK) {
|
||||
if (com.fastasyncworldedit.core.configuration.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_v4_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
try {
|
||||
setupBlockQueue();
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.apache.commons.lang.mutable.MutableInt;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import org.bukkit.Bukkit;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.util.image;
|
||||
package com.fastasyncworldedit.bukkit.util.image;
|
||||
|
||||
import com.boydti.fawe.util.image.Drawable;
|
||||
import com.boydti.fawe.util.image.ImageUtil;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.fastasyncworldedit.core.util.image.Drawable;
|
||||
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
@ -22,8 +22,8 @@ package com.sk89q.worldedit.bukkit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RunnableVal;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.wepif.VaultResolver;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -46,6 +46,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -392,11 +393,12 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
|
||||
} else {
|
||||
player.sendBlockChange(loc, BukkitAdapter.adapt(block));
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) {
|
||||
adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData());
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK && block instanceof BaseBlock) {
|
||||
CompoundBinaryTag nbt = ((BaseBlock) block).getNbt();
|
||||
if (nbt != null) {
|
||||
adapter.sendFakeNBT(player, pos, nbt);
|
||||
adapter.sendFakeOP(player);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.bukkit.NMSRelighterFactory;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.TuinityRelighterFactory_1_16_5;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.bukkit.util.CommandInfo;
|
||||
import com.sk89q.bukkit.util.CommandRegistration;
|
||||
@ -38,7 +36,6 @@ import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.extension.platform.Watchdog;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.registry.Registries;
|
||||
@ -70,7 +67,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
public final WorldEditPlugin plugin;
|
||||
private final CommandRegistration dynamicCommands;
|
||||
private final Lifecycled<Watchdog> watchdog;
|
||||
private final RelighterFactory relighterFactory;
|
||||
private RelighterFactory relighterFactory;
|
||||
private boolean hookingEvents;
|
||||
|
||||
public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
|
||||
@ -80,16 +77,6 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
this.watchdog = plugin.getLifecycledBukkitImplAdapter()
|
||||
.filter(BukkitImplAdapter::supportsWatchdog)
|
||||
.map(BukkitWatchdog::new);
|
||||
RelighterFactory tempFactory;
|
||||
try {
|
||||
Class.forName("com.tuinity.tuinity.config.TuinityConfig");
|
||||
tempFactory = new TuinityRelighterFactory_1_16_5();
|
||||
LOGGER.info("Using Tuinity internals for relighting");
|
||||
} catch (ClassNotFoundException e) {
|
||||
tempFactory = new NMSRelighterFactory();
|
||||
LOGGER.info("Using FAWE for relighting");
|
||||
}
|
||||
this.relighterFactory = tempFactory;
|
||||
}
|
||||
|
||||
CommandRegistration getDynamicCommands() {
|
||||
@ -144,7 +131,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public Watchdog getWatchdog() {
|
||||
return watchdog.valueOrThrow();
|
||||
return watchdog.value().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -262,6 +249,10 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public @NotNull RelighterFactory getRelighterFactory() {
|
||||
if (this.relighterFactory == null) {
|
||||
this.relighterFactory = this.plugin.getBukkitImplAdapter().getRelighterFactory();
|
||||
LOGGER.info("Using " + this.relighterFactory.getClass().getCanonicalName() + " as relighter factory.");
|
||||
}
|
||||
return this.relighterFactory;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -80,6 +80,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final boolean HAS_3D_BIOMES;
|
||||
private static final boolean HAS_MIN_Y;
|
||||
|
||||
private static final Map<Integer, Effect> effects = new HashMap<>();
|
||||
|
||||
@ -98,6 +99,13 @@ public class BukkitWorld extends AbstractWorld {
|
||||
temp = false;
|
||||
}
|
||||
HAS_3D_BIOMES = temp;
|
||||
try {
|
||||
World.class.getMethod("getMinHeight");
|
||||
temp = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
temp = false;
|
||||
}
|
||||
HAS_MIN_Y = temp;
|
||||
}
|
||||
|
||||
private WeakReference<World> worldRef;
|
||||
@ -143,7 +151,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return list;
|
||||
}
|
||||
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entitiy Add.
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entity Add.
|
||||
|
||||
/**
|
||||
* Get the world handle.
|
||||
@ -252,6 +260,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
if (!getBlock(pt).getBlockType().getMaterial().hasContainer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
BlockState state = PaperLib.getBlockState(block, false).getState();
|
||||
if (!(state instanceof InventoryHolder)) {
|
||||
@ -360,6 +369,14 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return getWorld().getMaxHeight() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
if (HAS_MIN_Y) {
|
||||
return getWorld().getMinHeight();
|
||||
}
|
||||
return super.getMinY();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void fixAfterFastMode(Iterable<BlockVector2> chunks) {
|
||||
@ -463,9 +480,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
try {
|
||||
return worldNativeAccess.setBlock(position, block, sideEffects);
|
||||
} catch (Exception e) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbt() != null) {
|
||||
LOGGER.warn("Tried to set a corrupt tile entity at " + position.toString()
|
||||
+ ": " + ((BaseBlock) block).getNbtData(), e);
|
||||
+ ": " + ((BaseBlock) block).getNbt(), e);
|
||||
} else {
|
||||
LOGGER.warn("Failed to set block via adapter, falling back to generic", e);
|
||||
}
|
||||
|
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