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>
This commit is contained in:
dordsor21 2021-07-01 21:16:25 +01:00 committed by GitHub
parent b0c0689887
commit aa3ae63682
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
798 changed files with 5101 additions and 16727 deletions

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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("")

View File

@ -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))
}
}

View File

@ -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") {

View File

@ -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)
}

View File

@ -4,6 +4,8 @@ plugins {
`java-library`
}
project.description = "Bukkit"
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
@ -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"))
}
}
}

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

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

View File

@ -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;

View File

@ -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());
} else {
WEManager.IMP.managers
.add(new com.boydti.fawe.bukkit.regions.plotsquared.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 {
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
}
}
}

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.adapter;
package com.fastasyncworldedit.bukkit.adapter;
public interface BukkitGetBlocks {

View File

@ -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;

View File

@ -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;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.adapter;
package com.fastasyncworldedit.bukkit.adapter;
import com.destroystokyo.paper.util.ReentrantLockWithGetOwner;

View File

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

View File

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter;
package com.fastasyncworldedit.bukkit.adapter;
import static com.google.common.base.Preconditions.checkNotNull;

View File

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

View File

@ -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 {

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
return 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;
}
@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();
final BlockVector3 to = BlockVector3
.at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
Clipboard holder = new BlockArrayClipboard(region, clipboard);
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
whenDone.run(tag);
});
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();
}
}
@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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotsquared;
package com.fastasyncworldedit.bukkit.regions.plotsquared;
import com.plotsquared.core.command.CommandCategory;

View File

@ -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;

View File

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

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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;
}

View File

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

Some files were not shown because too many files have changed in this diff Show More