feat!: Update for 1.18 (#1482)

* ci: Switch deployment to gh actions and use semver & java 17

* build: Update core dependencies

- Drop paranamer, you can access parameter names at runtime with Java 8+ natively

* ci: Snapshot builds are the default

* ci: Cleanup and finish transition

* ci: Trigger initial sync with the OSSRH

* revert: OSSRH snapshot deployment was successful, returning to baseline

This reverts commit 3a189f65f2.

* ci: Register javadoc jar for lib artifacts

* ci: Sign artifacts

* build: Set kotlin jvm toolchain

* style: Use minimized `version` output

* feat: Setup project structure for 1.18

* Exclude 1.17

* Port initial paperweight classes to 1.18 folder structure

* Move to Paper 1.18

* Update templates, address JEP deprecations and place a few TODOs

* Drop Guava 21 enforcement

* Make 1.18 to be effectively in a usable state (#1452)

* Update swathes of easy-to-update-sort-of-code.
 - Untested
 - Should compile but NMF broken something
 - Several todos:
  - biome history//better support (move to biome sections in core)
  - regen (haha lol no thanks, someone else can do that)
  - probably actually do the palette stuff that probably won't work in PaperweightPlatformAdapter

* ci: Provide basic Jenkinsfile for ghprb pipeline

* build: Update paperweight

* upstream: Update Upstream

de6fa17 Add getBrush helper for use with instanceof pattern matching (1926)

* FAWE will now load on startup

* it....works?

* Begin to allow biome edits (and fix biomes reverting to plains upon editing blocks)

* Add new blocks/block properties

* Only create biome palette if supplies is null

* Fix biome operations

* Finally get removing BlockID done (major version change allows it)

* refactor!: Drop PlotSquared v4

Fawe 2.0.0 and newer requires Java 17, PlotSquared v4 supports 1.13 and 1.14, Fawe wont work on these versions nevertheless and refuses to load due Java version incompatiblities with older versions. Newer versions can use PlotSquared v6.

* docs: Update readme

* Added and removed some comments

* Added and removed some comments

* refactor: Rename worldedit configuration

* build: Re-add 1.17 module

This the a very nasty commit

* chore: Implement missing methods

* build: Update paperweight

* upstream: Update upstream

6df194e Remove finalize, use a Cleaner instead (1943)
9843a4f Fix snapshots in 1.18 (1959)

* ci: Escape workflows

* build: Update paperweight to 1.18.1

* build: Update Paster

* Fix compilation

* Bump to 1.18.1

* Do both 1.18 and 1.18.1

Co-authored-by: Alex <mc.cache@web.de>

* Fix single-block lookups

* Reserve ordinals 0 through 3 for air/"reserved"

* Create block palette data with values

* Fix classpath for testing for starlight

* Correctly use block rather than sky light layer [not used in paper]

Co-authored-by: NotMyFault <mc.cache@web.de>
Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com>

* Update version (checking) for semver

* build: Fix release drafter base branch

* Trigger GHPRB

* tests: Add resource pack methods

* build: Update paperweight and add 1.17 again

* chore: Lazily change build delimiter

* build: Deploy API snapshots for 2.0.0

* Update adapters jar

* More verbosely get block data and ensure biome layer isn't null

* refactor: Address a few `TODO 1.18`'s

(cherry picked from commit 0b77932b6e46c825d78b8c7ccae2a68ad890564e)

* fix: Fix `/fawe debugpaste`

* refactor! Remove deprecations marked for removal that are not present in upstream (#1483)

* Reverse a "debug" change to BukkitImplLoader

* Fix parsing of build in FaweVersion

* refactor: Do prepared statements properly

- Update TextureUtil client jar to 1.18.1
- Limit the update checker to our domain

* Add classes with the correct minor version to the start of the adapter candidates list

* refactor: Deprecate `IMP` initializors in favor of builders

* Fix WEManager (#1487)

* Fix WeManager?

* Fix WeManager?

* Also register WEManager if not available, like TaskManager.

* refactor: Also deprecated `IMP` for DBHandler

* feat: Add a bunch of new types to the flora generator

* use spigot-compatible palette constructor

* use spigot-compatible packet constructor

* implement 1.18 regen

* return air instead of reserved on get blocks

* refactor: Shift `FileAlreadyExistsException` catch to a higher level

* read the actual block from ZeroBitStorage

* Add get default version min/max world height to platform
 - Fixes #1500

* Add methods to CLIPlatform

* Fix #1490

* Fix tests

* Don't force tick limiter enable/disable

* Use Math.floor instead of int cast 757bef1f7d2b16317ab3d18427ad22183344e28d

* More precise method names in MinecraftVersion
 - Also ensure correct comparisons are made in FaweBukkit and BukkitServerInterface
 - Fixes #1504

* Add back statically-set reserved IDs for air blocks only, make it clear they're "reserved" (#1502)

* Add back statically-set reserved IDs for air blocks only, make it clear they're "reserved"
Also:
 - Ensure that reserved is never returned in GET block operations
 - "empty" thus doesn't exist in the GET update methods; remove the needless checks
 - Allow GET/SET chunks to determine their own default values for non-present blocks/sections

* Add comments

* Remove mentions of NMS from compilation instruction

* Update log4j version, update jd links to use "latest"

* Move to BinaryTags where appropriate in adapters

* Add comments to changed code

* Rename worldedit to fawe where appropriate

* Use new language features

* chore: Format our loggers properly

* Remove unneeded comments

* Replace CachedChange class with record

* Remove/add some more comments

* Remove remaining keywords frm CachedChanged. IJ doesn't warn?

* Compress switch statements a bit using enhanced

* More enhanced switches

* Refactor: getVersionMin/MaxY -> versionMin/MaxY

* Throw, catch, and rethrow our own exception to make sure we're finding the culprit to a possible shaded-FAWE.

* Don't wrap Exception thrown upon invalid schematic path inside a RuntimeException
Fixes #1506

* docs: Put `since` annotation on newly introduced API

* docs: Drop clarified todos

* Warn user if using small-edit history setting with extended world heights

* Refactor: add javadoc to Clipboard#create and improve variables when delegating to another paste method

* Fix issue with offset/origin when pasting a clipboard via API without wrapping into a BlockArrayClipboard

* build: Remove drop our maven repository

* docs: Fix deprecation tag

* Fix incorrect toNative method in 1.17 adapter

* refactor: Deprecate tick limiter API for public use

* ci: dordsor does love rebasing here too

* docs: Document annotations

* Update upstream

fb5ec19 Fix error for snapshot restore missing chunk

* docs: Document a few undocumented annotations

* feat: Add worldedit.schematic.list.other permission and functionality (#1507)

* Add worldedit.schematic.list.other permission and functionality

* Implement StringMan#containsUuid

* Javadocs

* chore: Add since annotation

Co-authored-by: NotMyFault <mc.cache@web.de>

Co-authored-by: NotMyFault <mc.cache@web.de>
Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com>
Co-authored-by: Aurélien <43724816+Aurelien30000@users.noreply.github.com>
Co-authored-by: SirYwell <hannesgreule@outlook.de>
Co-authored-by: JOO200 <github@joo200.de>
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
This commit is contained in:
Alex 2022-01-05 16:58:30 +01:00 committed by GitHub
commit 8b973da7ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
234 changed files with 11428 additions and 4089 deletions

View File

@ -83,7 +83,7 @@ body:
attributes:
label: Fawe Version
description: What version of Fawe are you running? (`/version FastAsyncWorldEdit`)
placeholder: "For example: FastAsyncWorldEdit version 1.17-89;8c01959"
placeholder: "For example: FastAsyncWorldEdit version 2.0.0-SNAPSHOT-1"
validations:
required: true

2
.github/stale.yml vendored
View File

@ -1,4 +1,4 @@
daysUntilStale: 60
daysUntilStale: 30
daysUntilClose: 7
only: issues
exemptLabels:

View File

@ -1,34 +1,47 @@
name: "build"
name: build
on: ["pull_request", "push"]
on: [pull_request, push]
jobs:
build:
runs-on: "ubuntu-latest"
runs-on: ubuntu-latest
steps:
- name: "Checkout Repository"
uses: "actions/checkout@v2.3.4"
- name : "Validate Gradle Wrapper"
uses : "gradle/wrapper-validation-action@v1.0.4"
- name: "Grab SHA"
uses: "benjlevesque/short-sha@v1.2"
id: "short-sha"
- name: Checkout Repository
uses: actions/checkout@v2.4.0
- name : Validate Gradle Wrapper
uses : gradle/wrapper-validation-action@v1.0.4
- name: Setup Java
uses: actions/setup-java@v2.4.0
with:
length: "7"
- name: "Echo SHA"
run: "echo $SHA"
distribution: temurin
cache: gradle
java-version: 17
- name: Clean Build
run: ./gradlew clean build --no-daemon
- name: Determine release status
if: ${{ runner.os == 'Linux' }}
run: |
if [ "$(./gradlew properties | awk '/^version:/ { print $2; }' | grep '\-SNAPSHOT')" ]; then
echo "STATUS=snapshot" >> $GITHUB_ENV
else
echo "STATUS=release" >> $GITHUB_ENV
fi
- name: Publish Release
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18'}}
run: ./gradlew publishToSonatype closeSonatypeStagingRepository
env:
SHA: "${{ steps.short-sha.outputs.sha }}"
- name: "Setup Java"
uses: "actions/setup-java@v2.3.1"
with:
distribution: "temurin"
cache: 'gradle'
java-version: "17"
- name: "Clean Build"
run: "./gradlew clean build --no-daemon"
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
- name: Publish Snapshot
if: ${{ runner.os == 'Linux' && env.STATUS != 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18' }}
run: ./gradlew publishToSonatype
env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
- name: Archive Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v2.3.1
with:
name: FastAsyncWorldEdit-Bukkit-1.17-${{ env.SHA }}
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-1.17-${{ env.SHA }}.jar
name: FastAsyncWorldEdit-Bukkit-SNAPSHOT
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar

20
.github/workflows/rebase.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Rebase Pull Request
on:
issue_comment:
types: [created]
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') && github.event.comment.author_association == 'MEMBER'
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2.4.0
with:
token: ${{ secrets.REBASE_TOKEN }}
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.5
env:
GITHUB_TOKEN: ${{ secrets.REBASE_TOKEN }}

View File

@ -1,14 +1,14 @@
name: "draft release"
name: draft release
on:
push:
branches:
- "2.0.0"
- main
jobs:
update_release_draft:
runs-on: "ubuntu-latest"
runs-on: ubuntu-latest
steps:
- uses: "release-drafter/release-drafter@v5.15.0"
- uses: release-drafter/release-drafter@v5.15.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -0,0 +1,54 @@
:toc:
:toclevels: 2
= Fawe annotations explained
If we have modified parts of the WorldEdit codebase, we considered annotating it with different styles of comments, which
are explained in this document.
== In-line annotations
[source,java]
-----------------
public static Player adapt(com.sk89q.worldedit.entity.Player player) {
//FAWE start - Get player from PlayerProxy instead of BukkitPlayer if null
player = PlayerProxy.unwrap(player);
return player == null ? null : ((BukkitPlayer) player).getPlayer();
//FAWE end
}
-----------------
The `-sources` jar retains comments, if you add the FAWE API to your maven or gradle project, you can view differences between the projects with ease.
Behind the `//FAWE start - ` you can find a comment what has been changed and why it has been changed.
== Block annotations
[source,java]
-----------------
//FAWE start
@Override
public void setPermission(String permission, boolean value) {
}
//FAWE end
-----------------
Annotations can cover whole methods or go beyond the method and wrap around several added methods.
== Package annotations
Class additions are added under the `com.fastasyncworldedit` namespace, but sometimes classes need to be added in package private.
If that is done, you can find a `package-info.java` file within the package affected that outlines FAWE added classes:
[source,java]
-----------------
/**
* The following classes are FAWE additions:
*
* @see com.sk89q.worldedit.world.block.BlockTypesCache
*/
package com.sk89q.worldedit.world.block;
-----------------
== Undocumented annotations
Specific changes are not annotated:
* `com.fastasyncworldedit.core.configuration.Caption` in `com.sk89q.worldedit` packages have been changed from
`com.sk89q.worldedit.util.formatting.text.Text` to allow the usage of color codes for messages.
* Certain Log4J loggers have been adjusted to use the proper format of placeholders.

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 16 installed. Gradle will download JDK 16 specifically if needed,
You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed,
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 16.
You can get the JDK 16 [here](https://adoptium.net/).
You can get the JDK 17 [here](https://adoptium.net/).
The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules:
@ -16,10 +16,6 @@ The build process uses Gradle, which you do *not* need to download. FastAsyncWor
## To compile...
### 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](https://papermc.io/downloads) with `java -Dpaperclip.install=true -jar paperclip.jar`.
### On Windows
1. Shift + right-click the folder with FastAsyncWorldEdit's files and click "Open command prompt".
@ -38,13 +34,13 @@ You will find:
* FastAsyncWorldEdit for Bukkit in **worldedit-bukkit/build/libs**
* the CLI version in **worldedit-cli/build/libs**
If you want to use FastAsyncWorldEdit, use the `FastAsyncWorldEdit-1.17-<commitHash>` version obtained in **worldedit-bukkit/build/libs**.
If you want to use FastAsyncWorldEdit, use the `FastAsyncWorldEdit-<identifier>` version obtained in **worldedit-bukkit/build/libs**.
(The `-#` version includes FastAsyncWorldEdit + necessary libraries.)
## Other commands
* `gradlew idea` will generate an [IntelliJ IDEA](http://www.jetbrains.com/idea/) module for each folder.
* `gradlew idea` will generate an [IntelliJ IDEA](https://www.jetbrains.com/idea/) module for each folder.
_Possibly broken_:
* `gradlew eclipse` will generate an [Eclipse](https://www.eclipse.org/downloads/) project for each folder.

10
Jenkinsfile vendored
View File

@ -1,10 +0,0 @@
pipeline {
agent any
stages {
stage('Build pull request') {
steps {
sh './gradlew clean build'
}
}
}
}

View File

@ -12,7 +12,7 @@ FastAsyncWorldEdit is a fork of WorldEdit that has huge speed and memory improve
* Use it in creative, survival in single player or on your server.
* Use it on your Minecraft server to fix grieving and mistakes.
Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot, Paper, and Tuinity.
Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot and Paper.
## Download FastAsyncWorldEdit
* Spigot: https://www.spigotmc.org/resources/fast-async-worldedit.13932/
@ -24,8 +24,8 @@ 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 for the -bukkit module](https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Bukkit-Javadocs/javadoc/)
* [JavaDocs for the -core module](https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Core-Javadocs/javadoc/)
* [JavaDocs for the -bukkit module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Bukkit/latest/index.html)
* [JavaDocs for the -core module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Core/latest/index.html)
## Edit The Code

View File

@ -2,6 +2,11 @@ import org.ajoberstar.grgit.Grgit
import java.time.format.DateTimeFormatter
import org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED
import java.net.URI
plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
}
logger.lifecycle("""
*******************************************
@ -17,7 +22,8 @@ logger.lifecycle("""
*******************************************
""")
var rootVersion by extra("1.17")
var rootVersion by extra("2.0.0")
var snapshot by extra("SNAPSHOT")
var revision: String by extra("")
var buildNumber by extra("")
var date: String by extra("")
@ -27,11 +33,10 @@ ext {
}
date = git.head().dateTime.format(DateTimeFormatter.ofPattern("yy.MM.dd"))
revision = "-${git.head().abbreviatedId}"
val commit: String? = git.head().abbreviatedId
buildNumber = if (project.hasProperty("buildnumber")) {
project.properties["buildnumber"] as String
snapshot + "-" + project.properties["buildnumber"] as String
} else {
commit.toString()
project.properties["snapshot"] as String
}
}
@ -66,3 +71,12 @@ allprojects {
}
applyCommonConfiguration()
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
}
}

View File

@ -8,14 +8,17 @@ plugins {
repositories {
mavenCentral()
gradlePluginPortal()
maven {
name = "PaperMC"
url = uri("https://papermc.io/repo/repository/maven-public/")
}
maven {
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
}
maven {
name = "PaperMC"
url = uri("https://papermc.io/repo/repository/maven-public/")
content {
includeGroupByRegex("io\\.papermc\\..*")
}
}
}
val properties = Properties().also { props ->
@ -28,5 +31,11 @@ dependencies {
implementation(gradleApi())
implementation("org.ajoberstar.grgit:grgit-gradle:4.1.1")
implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.1")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.1.14")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.3.3")
}
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(17))
}
}

View File

@ -5,9 +5,7 @@ import org.gradle.kotlin.dsl.dependencies
// For specific version pinning, see
// https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
fun Project.applyPaperweightAdapterConfiguration(
paperVersion: String
) {
fun Project.applyPaperweightAdapterConfiguration() {
applyCommonConfiguration()
apply(plugin = "java-library")
applyCommonJavaConfiguration(
@ -17,7 +15,6 @@ fun Project.applyPaperweightAdapterConfiguration(
apply(plugin = "io.papermc.paperweight.userdev")
dependencies {
paperDevBundle(paperVersion)
"implementation"(project(":worldedit-bukkit"))
}

View File

@ -10,12 +10,7 @@ fun Project.applyCommonConfiguration() {
version = rootProject.version
repositories {
mavenLocal()
mavenCentral()
maven {
name = "IntellectualSites"
url = uri("https://mvn.intellectualsites.com/content/groups/public/")
}
maven {
name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/")
@ -32,6 +27,7 @@ fun Project.applyCommonConfiguration() {
name = "Athion"
url = uri("https://ci.athion.net/plugin/repository/tools/")
}
mavenLocal()
}
configurations.all {
@ -42,7 +38,7 @@ fun Project.applyCommonConfiguration() {
plugins.withId("java") {
the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(16))
languageVersion.set(JavaLanguageVersion.of(17))
}
}
@ -54,15 +50,15 @@ fun Project.applyCommonConfiguration() {
continue
}
add(conf.name, "com.google.guava:guava") {
version { require("21.0") }
version { require("31.0.1-jre") }
because("Mojang provides Guava")
}
add(conf.name, "com.google.code.gson:gson") {
version { require("2.8.0") }
version { require("2.8.8") }
because("Mojang provides Gson")
}
add(conf.name, "it.unimi.dsi:fastutil") {
version { require("8.2.1") }
version { require("8.5.6") }
because("Mojang provides FastUtil")
}
}

View File

@ -24,7 +24,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
val disabledLint = listOf(
"processing", "path", "fallthrough", "serial"
)
options.release.set(11)
options.release.set(17)
options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" })
options.isDeprecation = true
options.encoding = "UTF-8"
@ -32,7 +32,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
}
configurations.all {
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 16)
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
tasks.withType<Test>().configureEach {
@ -60,13 +60,12 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
options.encoding = "UTF-8"
links(
"https://javadoc.io/doc/com.google.code.findbugs/jsr305/3.0.2/",
"https://jd.adventure.kyori.net/api/4.9.1/",
"https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/2.14.1/",
"https://javadoc.io/doc/com.google.guava/guava/21.0/",
"https://jd.adventure.kyori.net/api/latest/",
"https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/latest/index.html",
"https://www.antlr.org/api/Java/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/",
"https://papermc.io/javadocs/paper/1.17/",
"https://papermc.io/javadocs/paper/1.18/",
"https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Core-Javadocs/javadoc/" // needed for other module linking
)
}

View File

@ -21,6 +21,8 @@ import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the
import org.gradle.plugins.signing.SigningExtension
import javax.inject.Inject
fun Project.applyLibrariesConfiguration() {
@ -28,6 +30,7 @@ fun Project.applyLibrariesConfiguration() {
apply(plugin = "java-base")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "signing")
configurations {
create("shade")
@ -49,6 +52,7 @@ fun Project.applyLibrariesConfiguration() {
dependencies {
exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("com.google.errorprone:error_prone_annotations"))
exclude(dependency("org.checkerframework:checker-qual"))
exclude(dependency("org.apache.logging.log4j:log4j-api"))
exclude(dependency("com.google.code.findbugs:jsr305"))
@ -94,8 +98,14 @@ fun Project.applyLibrariesConfiguration() {
archiveClassifier.set("sources")
}
// This a dummy jar to comply with the requirements of the OSSRH,
// libs are not API and therefore no "proper" javadoc jar is necessary
tasks.register<Jar>("javadocJar") {
archiveClassifier.set("javadoc")
}
tasks.named("assemble").configure {
dependsOn("jar", "sourcesJar")
dependsOn("jar", "sourcesJar", "javadocJar")
}
project.apply<LibsConfigPluginHack>()
@ -112,7 +122,7 @@ fun Project.applyLibrariesConfiguration() {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11)
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
outgoing.artifact(tasks.named("jar"))
}
@ -127,7 +137,7 @@ fun Project.applyLibrariesConfiguration() {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements.JAR))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11)
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
outgoing.artifact(tasks.named("jar"))
}
@ -146,6 +156,20 @@ fun Project.applyLibrariesConfiguration() {
outgoing.artifact(tasks.named("sourcesJar"))
}
val javadocElements = project.configurations.register("javadocElements") {
isVisible = false
description = "Javadoc elements for libs"
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.DOCUMENTATION))
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.SHADOWED))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.objects.named(DocsType.JAVADOC))
}
outgoing.artifact(tasks.named("javadocJar"))
}
libsComponent.addVariantsFromConfiguration(apiElements.get()) {
mapToMavenScope("compile")
}
@ -158,6 +182,22 @@ fun Project.applyLibrariesConfiguration() {
mapToMavenScope("runtime")
}
libsComponent.addVariantsFromConfiguration(javadocElements.get()) {
mapToMavenScope("runtime")
}
val publishingExtension = the<PublishingExtension>()
configure<SigningExtension> {
if (!version.toString().endsWith("-SNAPSHOT")) {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
isRequired
sign(publishingExtension.publications)
}
}
configure<PublishingExtension> {
publications {
register<MavenPublication>("maven") {
@ -212,33 +252,6 @@ fun Project.applyLibrariesConfiguration() {
}
}
}
repositories {
mavenLocal()
val nexusUsername: String? by project
val nexusPassword: String? by project
if (nexusUsername != null && nexusPassword != null) {
maven {
val releasesRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/releases/"
val snapshotRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/snapshots/"
/* Commenting this out for now - Fawe currently does not user semver or any sort of versioning that
differentiates between snapshots and releases, API & (past) deployment wise, this will come with a next major release.
url = uri(
if (version.toString().endsWith("-SNAPSHOT")) snapshotRepositoryUrl
else releasesRepositoryUrl
)
*/
url = uri(releasesRepositoryUrl)
credentials {
username = nexusUsername
password = nexusPassword
}
}
} else {
logger.warn("No nexus repository is added; nexusUsername or nexusPassword is null.")
}
}
}
}

View File

@ -12,6 +12,7 @@ import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the
import org.gradle.plugins.signing.SigningExtension
fun Project.applyPlatformAndCoreConfiguration() {
applyCommonConfiguration()
@ -20,6 +21,7 @@ fun Project.applyPlatformAndCoreConfiguration() {
apply(plugin = "idea")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "signing")
applyCommonJavaConfiguration(
sourcesJar = name in setOf("worldedit-core", "worldedit-bukkit"),
@ -45,6 +47,18 @@ fun Project.applyPlatformAndCoreConfiguration() {
skip()
}
val publishingExtension = the<PublishingExtension>()
configure<SigningExtension> {
if (!version.toString().endsWith("-SNAPSHOT")) {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
isRequired
sign(publishingExtension.publications)
}
}
configure<PublishingExtension> {
publications {
register<MavenPublication>("maven") {
@ -99,33 +113,6 @@ fun Project.applyPlatformAndCoreConfiguration() {
}
}
}
repositories {
mavenLocal()
val nexusUsername: String? by project
val nexusPassword: String? by project
if (nexusUsername != null && nexusPassword != null) {
maven {
val releasesRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/releases/"
val snapshotRepositoryUrl = "https://mvn.intellectualsites.com/content/repositories/snapshots/"
/* Commenting this out for now - Fawe currently does not user semver or any sort of versioning that
differentiates between snapshots and releases, API & (past) deployment wise, this will come with a next major release.
url = uri(
if (version.toString().endsWith("-SNAPSHOT")) snapshotRepositoryUrl
else releasesRepositoryUrl
)
*/
url = uri(releasesRepositoryUrl)
credentials {
username = nexusUsername
password = nexusPassword
}
}
} else {
logger.warn("No nexus repository is added; nexusUsername or nexusPassword is null.")
}
}
}
if (name != "worldedit-fabric") {

View File

@ -1,12 +1,12 @@
[versions]
# Minecraft expectations
fastutil = "8.2.1"
log4j = "2.17.0"
guava = "21.0"
gson = "2.8.0"
fastutil = "8.5.6"
log4j = "2.17.1"
guava = "31.0.1-jre"
gson = "2.8.8"
# Platform expectations
paper = "1.17.1-R0.1-SNAPSHOT"
paper = "1.18.1-R0.1-SNAPSHOT"
# Plugins
vault = "1.7.1"
@ -20,15 +20,14 @@ residence = "4.5._13.1"
towny = "0.97.5.0"
protocollib = "4.7.0"
plotsquaredV6 = "6.2.0"
plotsquaredV4 = "4.514"
redprotect = "1.9.6"
# Third party
flow-math = "1.0.3"
paperlib = "1.0.7"
paperlib = "1.0.8-SNAPSHOT"
bstats = "2.2.1"
serverlib = "2.3.1"
paster = "1.1.1"
paster = "1.1.3"
sparsebitset = "1.2"
parallelgzip = "1.0.5"
adventure = "4.9.3"
@ -39,7 +38,6 @@ rhino-runtime = "1.7.13"
zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs
antlr4 = "4.9.3"
json-simple = "1.1.1"
paranamer = "2.8"
jlibnoise = "1.0.0"
jchronic = "0.2.4a"
lz4-java = "1.8.0"
@ -81,7 +79,6 @@ towny = { group = "com.github.TownyAdvanced", name = "Towny", version.ref = "tow
protocollib = { group = "com.comphenix.protocol", name = "ProtocolLib", version.ref = "protocollib" }
plotsquaredV6Bukkit = { group = "com.plotsquared", name = "PlotSquared-Bukkit", version.ref = "plotsquaredV6" }
plotsquaredV6Core = { group = "com.plotsquared", name = "PlotSquared-Core", version.ref = "plotsquaredV6" }
plotsquaredV4 = { group = "com.github.intellectualsites.plotsquared", name = "PlotSquared-API", version.ref = "plotsquaredV4" }
redprotect = { group = "net.fabiozumbi12", name = "redprotect", version.ref = "redprotect" }
# Third Party
@ -104,7 +101,6 @@ zstd = { group = "com.github.luben", name = "zstd-jni", version.ref = "zstd-jni"
antlr4 = { group = "org.antlr", name = "antlr4", version.ref = "antlr4" }
antlr4Runtime = { group = "org.antlr", name = "antlr4-runtime", version.ref = "antlr4" }
jsonSimple = { group = "com.googlecode.json-simple", name = "json-simple", version.ref = "json-simple" }
paranamer = { group = "com.thoughtworks.paranamer", name = "paranamer", version.ref = "paranamer" }
jlibnoise = { group = "com.sk89q.lib", name = "jlibnoise", version.ref = "jlibnoise" }
jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" }
lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" }

View File

@ -10,7 +10,6 @@
"mockito-core",
"org.antlr",
"antlr4-runtime",
"paranamer",
"fastutil",
"it.unimi.dsi:fastutil",
"auto-value-annotations",

View File

@ -4,6 +4,7 @@ include("worldedit-libs")
include("worldedit-bukkit:adapters:adapter-legacy")
include("worldedit-bukkit:adapters:adapter-1_17_1")
include("worldedit-bukkit:adapters:adapter-1_18")
listOf("bukkit", "core", "cli").forEach {
include("worldedit-libs:$it")

View File

@ -1,21 +1,27 @@
applyPaperweightAdapterConfiguration()
plugins {
java
}
applyPaperweightAdapterConfiguration(
"1.17.1-R0.1-20211210.043523-198"
)
repositories {
mavenCentral()
maven {
name = "PaperMC"
url = uri("https://papermc.io/repo/repository/maven-public/")
content {
includeModule("io.papermc", "paperlib")
}
}
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
configurations.all {
attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
dependencies {
paperDevBundle("1.17.1-R0.1-20211219.175449-201")
compileOnly(libs.paperlib)
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.bukkit.adapter.ext.fawe;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@ -35,8 +36,10 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
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.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightFaweAdapter;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.extent.Extent;
@ -53,6 +56,7 @@ import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
@ -168,11 +172,11 @@ import static com.google.common.base.Preconditions.checkState;
public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> {
private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName());
private final Field serverWorldsField;
private final Method getChunkFutureMethod;
private final Field chunkProviderExecutorField;
private final Field worldsField;
private final Method getChunkFutureMainThreadMethod;
private final Field mainThreadProcessorField;
private final Watchdog watchdog;
// ------------------------------------------------------------------------
@ -188,18 +192,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
throw new UnsupportedClassVersionError("Not 1.17.1!");
}
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
worldsField = CraftServer.class.getDeclaredField("worlds");
worldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod("getChunkFutureMainThread",
getChunkFutureMainThreadMethod = ServerChunkCache.class.getDeclaredMethod("getChunkFutureMainThread",
int.class, int.class, ChunkStatus.class, boolean.class
);
getChunkFutureMethod.setAccessible(true);
getChunkFutureMainThreadMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
mainThreadProcessorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "h")
);
chunkProviderExecutorField.setAccessible(true);
mainThreadProcessorField.setAccessible(true);
new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).build(ForkJoinPool.commonPool());
@ -316,9 +320,31 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId);
}
@Deprecated
@Override
public BaseBlock getBlock(Location location) {
checkNotNull(location);
public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData();
BlockState state = BukkitAdapter.adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
}
@Override
public BaseBlock getFullBlock(Location location) {
BlockState state = getBlock(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
@ -328,19 +354,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
// Read the NBT data
BlockEntity te = chunk.getBlockEntity(blockPos);
if (te != null) {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
readTileEntityIntoTag(te, tag); // Load data
net.minecraft.nbt.CompoundTag tag = te.save(new net.minecraft.nbt.CompoundTag());
//FAWE start - BinaryTag
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag));
//FAWE end
@ -418,7 +436,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, tag);
return new BaseEntity(com.sk89q.worldedit.world.entity.EntityTypes.get(id), (CompoundTag) toNative(tag));
//FAWE start - BinaryTag
return new BaseEntity(
com.sk89q.worldedit.world.entity.EntityTypes.get(id),
LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag))
);
//FAWE end
}
@Nullable
@ -500,7 +523,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
property = new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName());
}
properties.put(property.getName(), property);
@ -650,7 +673,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally {
try {
@SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) worldsField.get(Bukkit.getServer());
map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) {
}
@ -723,7 +746,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld);
BlockableEventLoop<Runnable> executor;
try {
executor = (BlockableEventLoop<Runnable>) chunkProviderExecutorField.get(serverWorld.getChunkSource());
executor = (BlockableEventLoop<Runnable>) mainThreadProcessorField.get(serverWorld.getChunkSource());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Couldn't get executor for chunk loading.", e);
}
@ -748,8 +771,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ());
ChunkAccess chunk = chunks.get(new ChunkPos(pos));
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos);
int internalId = Block.getId(blockData);
BlockStateHolder<?> state = BlockStateIdAccess.getBlockStateById(internalId);
BlockStateHolder<?> state = ((PaperweightFaweAdapter) WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()).adapt(blockData);
Objects.requireNonNull(state);
BlockEntity blockEntity = chunk.getBlockEntity(pos);
if (blockEntity != null) {
@ -783,7 +807,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
//noinspection unchecked
chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true))
getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null))
);
} catch (IllegalAccessException | InvocationTargetException e) {
@ -875,7 +899,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try {
return toNativeList((net.minecraft.nbt.ListTag) foreign);
} catch (Throwable e) {
logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
return ListBinaryTag.empty();
}
} else if (foreign instanceof net.minecraft.nbt.LongTag) {
@ -994,7 +1018,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
WatchdogThread.tick();
}
} catch (IllegalAccessException e) {
logger.log(Level.WARNING, "Failed to tick watchdog", e);
LOGGER.log(Level.WARNING, "Failed to tick watchdog", e);
}
}

View File

@ -11,8 +11,6 @@ import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack;
@ -40,6 +38,9 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -230,9 +231,29 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource()));
}
@SuppressWarnings("deprecation")
@Deprecated
@Override
public BaseBlock getBlock(Location location) {
public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
}
@Override
public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
@ -240,19 +261,22 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel serverLevel = craftWorld.getHandle();
LevelChunk levelChunk = serverLevel.getChunk(x >> 4, z >> 4);
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
org.bukkit.block.Block bukkitBlock = location.getBlock();
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
if (state.getBlockType().getMaterial().hasContainer()) {
// Read the NBT data
BlockEntity blockEntity = levelChunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
blockEntity.save(tag); // readTileEntityIntoTag - load data
return state.toBaseBlock((CompoundTag) toNative(tag));
net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag());
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag));
}
}
@ -284,7 +308,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
CompoundTag compoundTag = state instanceof BaseBlock ? state.getNbtData() : null;
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
if (compoundTag != null || existing instanceof TileEntityBlock) {
level.setBlock(blockPos, blockState, 0);
// remove tile
@ -293,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// though we do not do this on the Forge version
BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(compoundTag);
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z));
@ -337,14 +361,15 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundTag> saveTag = () -> {
Supplier<CompoundBinaryTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", new StringTag(id));
return new CompoundTag(tags);
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
final Map<String, BinaryTag> tags = new HashMap<>();
tag.keySet().forEach(key -> tags.put(key, tag.get(key)));
tags.put("Id", StringBinaryTag.of(id));
return CompoundBinaryTag.from(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
@ -401,7 +426,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
);
return 0;
return BlockTypesCache.ReservedIDs.AIR;
}
}
}
@ -486,10 +511,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
chunkPacket.setNativePacket(nmsPacket);
}
try {
FaweCache.IMP.CHUNK_FLAG.get().set(true);
FaweCache.INSTANCE.CHUNK_FLAG.get().set(true);
entityPlayer.connection.send(nmsPacket);
} finally {
FaweCache.IMP.CHUNK_FLAG.get().set(false);
FaweCache.INSTANCE.CHUNK_FLAG.get().set(false);
}
}
});
@ -517,7 +542,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())),
baseItemStack.getAmount()
);
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt())));
return CraftItemStack.asCraftMirror(stack);
}
@ -579,7 +604,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag())));
return weStack;
}

View File

@ -250,7 +250,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
}
}
};
TaskManager.IMP.async(() -> TaskManager.IMP.sync(runnableVal));
TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
}
@Override
@ -269,27 +269,17 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
if (Fawe.isMainThread()) {
runnableVal.run();
} else {
TaskManager.IMP.sync(runnableVal);
TaskManager.taskManager().sync(runnableVal);
}
cachedChanges.clear();
cachedChunksToSend.clear();
}
private static final class CachedChange {
private final LevelChunk levelChunk;
private final BlockPos blockPos;
private final net.minecraft.world.level.block.state.BlockState blockState;
private CachedChange(
LevelChunk levelChunk,
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
this.levelChunk = levelChunk;
this.blockPos = blockPos;
this.blockState = blockState;
}
private record CachedChange(
LevelChunk levelChunk,
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
}

View File

@ -25,7 +25,7 @@ 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 com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos;
@ -151,7 +151,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (light != null) {
lightUpdate = true;
try {
fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition);
fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition);
} catch (Throwable e) {
e.printStackTrace();
}
@ -419,7 +419,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
try {
ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE;
// Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
@ -546,25 +546,30 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
}
// Biomes
BiomeType[] biomes = set.getBiomes();
BiomeType[][] biomes = set.getBiomes();
if (biomes != null) {
// set biomes
ChunkBiomeContainer currentBiomes = nmsChunk.getBiomes();
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) {
Biome nmsBiome =
nmsWorld.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).get(
ResourceLocation.tryParse(biome.getId()));
if (nmsBiome == null) {
throw new NullPointerException("BiomeBase null for BiomeType " + biome.getId());
for (int layer = 0; layer < 16; layer++) {
if (biomes[layer] == null) {
continue;
}
for (int y = 0, i = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, i++) {
final BiomeType biome = biomes[layer][i];
if (biome != null) {
Biome nmsBiome =
nmsWorld.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).get(
ResourceLocation.tryParse(biome.getId()));
if (nmsBiome == null) {
throw new NullPointerException("BiomeBase null for BiomeType " + biome.getId());
}
currentBiomes.setBiome(x, (layer << 2) + y, z, nmsBiome);
}
currentBiomes.setBiome(x, y, z, nmsBiome);
}
}
}
@ -722,7 +727,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
nmsChunk.mustNotSave = false;
nmsChunk.markUnsaved();
// send to player
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) {
this.send(finalMask, finalLightUpdate);
}
if (finalizer != null) {
@ -731,7 +736,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
};
}
if (syncTasks != null) {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
QueueHandler queueHandler = Fawe.instance().getQueueHandler();
Runnable[] finalSyncTasks = syncTasks;
// Chain the sync tasks and the callback
@ -756,6 +761,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
throw e;
}
};
//noinspection unchecked - required at compile time
return (T) (Future) queueHandler.sync(chain);
} else {
if (callback == null) {
@ -840,16 +846,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
// Section is null, return empty array
if (section == null) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
return data;
}
if (data != null && data.length != 4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) {
data = new char[4096];
Arrays.fill(data, (char) 1);
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) {
@ -874,13 +880,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char ordinal = adapter.ibdIDToOrdinal(paletteVal);
// Don't read "empty".
data[i] = ordinal == 0 ? 1 : ordinal;
data[i] = ordinal;
}
return data;
}
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get();
try {
if (num_palette != 1) {
for (int i = 0; i < num_palette; i++) {
@ -894,18 +899,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
val = ordinal(palette.valueFor(i), adapter);
paletteToOrdinal[i] = val;
}
// Don't read "empty".
if (val == 0) {
val = 1;
}
data[i] = val;
}
} else {
char ordinal = ordinal(palette.valueFor(0), adapter);
// Don't read "empty".
if (ordinal == 0) {
ordinal = 1;
}
Arrays.fill(data, ordinal);
}
} finally {
@ -925,7 +922,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) {
if (ibd == null) {
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
return BlockTypesCache.ReservedIDs.AIR;
} else {
return adapter.adaptToChar(ibd);
}

View File

@ -86,7 +86,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final long fieldLockOffset;
private static final Field fieldGameEventDispatcherSections;
private static final MethodHandle methodremoveTickingBlockEntity;
private static final MethodHandle methodremoveBlockEntityTicker;
private static final Field fieldRemove;
@ -133,7 +133,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
methodremoveBlockEntityTicker = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true);
@ -215,7 +215,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
e.printStackTrace();
}
}
return TaskManager.IMP.sync(() -> serverLevel.getChunk(chunkX, chunkZ));
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
@ -247,7 +247,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return;
}
LevelChunk levelChunk = optional.get();
TaskManager.IMP.task(() -> {
TaskManager.taskManager().task(() -> {
ClientboundLevelChunkPacket chunkPacket = new ClientboundLevelChunkPacket(levelChunk);
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(chunkPacket));
if (lighting) {
@ -283,10 +283,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
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();
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try {
int[] num_palette_buffer = new int[1];
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
@ -303,7 +303,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
int num_palette = num_palette_buffer[0];
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
@ -440,7 +440,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldRemove.set(beacon, true);
}
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
methodremoveBlockEntityTicker.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
}

View File

@ -129,7 +129,7 @@ public class PaperweightStarlightRelighter implements Relighter {
while (iterator.hasNext()) {
coords.add(new ChunkPos(iterator.nextLong()));
}
TaskManager.IMP.task(() -> {
TaskManager.taskManager().task(() -> {
// trigger chunk load and apply ticket on main thread
List<CompletableFuture<?>> futures = new ArrayList<>();
for (ChunkPos pos : coords) {
@ -153,9 +153,9 @@ public class PaperweightStarlightRelighter implements Relighter {
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
}
// post process chunks on main thread
TaskManager.IMP.task(() -> postProcessChunks(coords));
TaskManager.taskManager().task(() -> postProcessChunks(coords));
// call callback on our own threads
TaskManager.IMP.async(andThen);
TaskManager.taskManager().async(andThen);
}
)
);
@ -184,7 +184,7 @@ public class PaperweightStarlightRelighter implements Relighter {
* Also, if chunk packets are sent delayed, we need to do that here
*/
private void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.IMP.LIGHTING.DELAY_PACKET_SENDING;
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;

View File

@ -66,8 +66,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public double asDouble(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag) {
return ((NumericTag) tag).getAsDouble();
if (tag instanceof NumericTag numTag) {
return numTag.getAsDouble();
}
return 0;
}
@ -86,20 +86,19 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public int asInt(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag) {
return ((NumericTag) tag).getAsInt();
if (tag instanceof NumericTag numTag) {
return numTag.getAsInt();
}
return 0;
}
public List<Tag> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag) {
if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag> list = new ArrayList<>();
net.minecraft.nbt.ListTag nbtList = (net.minecraft.nbt.ListTag) tag;
for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag) {
list.add(new PaperweightLazyCompoundTag((net.minecraft.nbt.CompoundTag) elem));
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag));
} else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
}
@ -137,8 +136,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public long asLong(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag) {
return ((NumericTag) tag).getAsLong();
if (tag instanceof NumericTag numTag) {
return numTag.getAsLong();
}
return 0;
}

View File

@ -90,13 +90,13 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field worldPaperConfigField;
private static final Field flatBedrockField;
private static final Field worldsField;
private static final Field paperConfigField;
private static final Field generateFlatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkProviderField;
private static final Field chunkSourceField;
//list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
@ -125,8 +125,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
worldsField = CraftServer.class.getDeclaredField("worlds");
worldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
@ -140,8 +140,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
worldPaperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
paperConfigField = tmpPaperConfigField;
generateFlatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "g"));
@ -153,8 +153,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkProviderField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C"));
chunkProviderField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C"));
chunkSourceField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
@ -187,9 +187,9 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
}
//flat bedrock? (only on paper)
if (worldPaperConfigField != null) {
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalServerWorld));
generateFlatBedrock = generateFlatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
@ -210,7 +210,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("worldeditregentempworld", levelStemResourceKey);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
@ -221,7 +221,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
? PaperweightAdapter.replaceSeed(originalServerWorld, seed, originalOpts)
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"worldeditregentempworld",
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
@ -232,7 +232,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, Lifecycle.stable());
//init world
freshWorld = Fawe.get().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
@ -270,8 +270,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (worldPaperConfigField != null) {
worldPaperConfigField.set(freshWorld, originalServerWorld.paperConfig);
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig);
}
//generator
@ -319,7 +319,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
}
};
ReflectionUtils.unsafeSet(chunkProviderField, freshWorld, freshChunkProvider);
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureManager = server.getStructureManager();
threadedLevelLightEngine = freshChunkProvider.getLightEngine();
@ -336,7 +336,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
//shutdown chunk provider
try {
Fawe.get().getQueueHandler().sync(() -> {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (IOException e) {
@ -348,7 +348,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
//remove world from server
try {
Fawe.get().getQueueHandler().sync(this::removeWorldFromWorldsMap);
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
@ -388,7 +388,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.IMP.task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk()));
TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk()));
}
@Override
@ -403,10 +403,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
//util
private void removeWorldFromWorldsMap() {
Fawe.get().getQueueHandler().sync(() -> {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("worldeditregentempworld");
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) worldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
@ -414,15 +414,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
switch (env) {
case NETHER:
return LevelStem.NETHER;
case THE_END:
return LevelStem.END;
case NORMAL:
default:
return LevelStem.OVERWORLD;
}
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception {

View File

@ -0,0 +1,17 @@
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
maven {
name = "PaperMC"
url = uri("https://papermc.io/repo/repository/maven-public/")
}
}
dependencies {
paperDevBundle("1.18.1-R0.1-20211221.093324-19")
compileOnly(libs.paperlib)
}

View File

@ -0,0 +1,103 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ServerboundClientInformationPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.OptionalInt;
import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(
UUID.nameUUIDFromBytes("worldedit".getBytes()),
"[WorldEdit]"
);
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE);
}
@Override
public Vec3 position() {
return ORIGIN;
}
@Override
public void tick() {
}
@Override
public void die(DamageSource damagesource) {
}
@Override
public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) {
return this;
}
@Override
public OptionalInt openMenu(MenuProvider factory) {
return OptionalInt.empty();
}
@Override
public void updateOptions(ServerboundClientInformationPacket packet) {
}
@Override
public void displayClientMessage(Component message, boolean actionBar) {
}
@Override
public void sendMessage(Component message, ChatType type, UUID sender) {
}
@Override
public void awardStat(Stat<?> stat, int amount) {
}
@Override
public void awardStat(Stat<?> stat) {
}
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {
return true;
}
@Override
public void openTextEdit(SignBlockEntity sign) {
}
}

View File

@ -0,0 +1,209 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class PaperweightWorldNativeAccess implements
WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private final PaperweightAdapter adapter;
private final WeakReference<ServerLevel> world;
private SideEffectSet sideEffectSet;
public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference<ServerLevel> world) {
this.adapter = adapter;
this.world = world;
}
private ServerLevel getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState setBlockState(
LevelChunk chunk,
BlockPos position,
net.minecraft.world.level.block.state.BlockState state
) {
return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(
net.minecraft.world.level.block.state.BlockState block,
BlockPos position
) {
return Block.updateFromNeighbourShapes(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkSource().getLightEngine().checkBlock(position);
}
@Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) {
return false;
}
@Override
public void notifyBlockUpdate(
LevelChunk chunk,
BlockPos position,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
}
@Override
public void markBlockChanged(LevelChunk chunk, BlockPos position) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().getChunkSource().blockChanged(position);
}
}
@Override
public void notifyNeighbors(
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
ServerLevel world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.updateNeighborsAt(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
Block block = oldState.getBlock();
fireNeighborChanged(pos, world, block, pos.west());
fireNeighborChanged(pos, world, block, pos.east());
fireNeighborChanged(pos, world, block, pos.below());
fireNeighborChanged(pos, world, block, pos.above());
fireNeighborChanged(pos, world, block, pos.north());
fireNeighborChanged(pos, world, block, pos.south());
}
if (newState.hasAnalogOutputSignal()) {
world.updateNeighbourForOutputSignal(pos, newState.getBlock());
}
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false);
}
@Override
public void updateNeighbors(
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState,
int recursionLimit
) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent(
craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()),
CraftBlockData.fromData(newState)
);
world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(
BlockPos pos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
@Override
public void flush() {
}
}

View File

@ -0,0 +1,189 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
public class PaperweightBlockMaterial implements BlockMaterial {
private final Block block;
private final BlockState blockState;
private final Material material;
private final boolean isTranslucent;
private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial;
private final int opacity;
private final CompoundTag tile;
public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState());
}
public PaperweightBlockMaterial(Block block, BlockState blockState) {
this.block = block;
this.blockState = blockState;
this.material = blockState.getMaterial();
this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial();
BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName(
"properties", "aP"));
this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo,
Refraction.pickName("canOcclude", "n")
);
opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
BlockPos.ZERO,
blockState
);
tile = tileEntity == null
? null
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
}
public Block getBlock() {
return block;
}
public BlockState getState() {
return blockState;
}
public CraftBlockData getCraftBlockData() {
return craftBlockData;
}
public Material getMaterial() {
return material;
}
@Override
public boolean isAir() {
return blockState.isAir();
}
@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
}
@Override
public boolean isOpaque() {
return material.isSolidBlocking();
}
@Override
public boolean isPowerSource() {
return blockState.isSignalSource();
}
@Override
public boolean isLiquid() {
return material.isLiquid();
}
@Override
public boolean isSolid() {
return material.isSolid();
}
@Override
public float getHardness() {
return craftBlockData.getState().destroySpeed;
}
@Override
public float getResistance() {
return block.getExplosionResistance();
}
@Override
public float getSlipperiness() {
return block.getFriction();
}
@Override
public int getLightValue() {
return blockState.getLightEmission();
}
@Override
public int getLightOpacity() {
return opacity;
}
@Override
public boolean isFragileWhenPushed() {
return material.getPushReaction() == PushReaction.DESTROY;
}
@Override
public boolean isUnpushable() {
return material.getPushReaction() == PushReaction.BLOCK;
}
@Override
public boolean isTicksRandomly() {
return block.isRandomlyTicking(blockState);
}
@Override
public boolean isMovementBlocker() {
return material.isSolid();
}
@Override
public boolean isBurnable() {
return material.isFlammable();
}
@Override
public boolean isToolRequired() {
// Removed in 1.16.1, this is not present in higher versions
return false;
}
@Override
public boolean isReplacedDuringPlacement() {
return material.isReplaceable();
}
@Override
public boolean isTranslucent() {
return isTranslucent;
}
@Override
public boolean hasContainer() {
return block instanceof EntityBlock;
}
@Override
public boolean isTile() {
return block instanceof EntityBlock;
}
@Override
public CompoundTag getDefaultTile() {
return tile;
}
@Override
public int getMapColor() {
// rgb field
return material.getColor().col;
}
}

View File

@ -0,0 +1,689 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1.PaperweightAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.nbt.IntTag;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.TreeType;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_18_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlockState;
import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
IDelegateBukkitImplAdapter<net.minecraft.nbt.Tag> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new PaperweightAdapter();
}
@Nullable
private static String getEntityId(Entity entity) {
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
return resourceLocation == null ? null : resourceLocation.toString();
}
private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) {
entity.save(compoundTag);
}
@Override
public BukkitImplAdapter<net.minecraft.nbt.Tag> getParent() {
return parent;
}
private synchronized boolean init() {
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState blockState = BlockTypesCache.states[i];
PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial();
int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState());
char ordinal = blockState.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
Map<String, List<Property<?>>> properties = new HashMap<>();
try {
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
Object obj = field.get(null);
if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property<?> state)) {
continue;
}
Property<?> property;
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
property = new BooleanProperty(
state.getName(),
(List<Boolean>) ImmutableList.copyOf(state.getPossibleValues())
);
} else if (state instanceof DirectionProperty) {
property = new DirectionalProperty(
state.getName(),
state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase()))
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
property = new EnumProperty(
state.getName(),
state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
property = new IntegerProperty(
state.getName(),
(List<Integer>) ImmutableList.copyOf(state.getPossibleValues())
);
} else {
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> {
if (v == null) {
v = new ArrayList<>(Collections.singletonList(property));
} else {
v.add(property);
}
return v;
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
allBlockProperties = ImmutableMap.copyOf(properties);
}
initialised = true;
return true;
}
@Override
public BlockMaterial getMaterial(BlockType blockType) {
Block block = getBlock(blockType);
return new PaperweightBlockMaterial(block);
}
@Override
public synchronized BlockMaterial getMaterial(BlockState state) {
net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
return new PaperweightBlockMaterial(blockState.getBlock(), blockState);
}
public Block getBlock(BlockType blockType) {
return Registry.BLOCK.get(new ResourceLocation(blockType.getNamespace(), blockType.getResource()));
}
@Deprecated
@Override
public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
}
@Override
public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
if (state.getBlockType().getMaterial().hasContainer()) {
// Read the NBT data
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag));
}
}
return state.toBaseBlock();
}
@Override
public Set<SideEffect> getSupportedSideEffects() {
return SideEffectSet.defaults().getSideEffectsToApply();
}
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk;
LevelChunk levelChunk = craftChunk.getHandle();
Level level = levelChunk.getLevel();
BlockPos blockPos = new BlockPos(x, y, z);
net.minecraft.world.level.block.state.BlockState blockState = ((PaperweightBlockMaterial) state.getMaterial()).getState();
LevelChunkSection[] levelChunkSections = levelChunk.getSections();
int y4 = y >> 4;
LevelChunkSection section = levelChunkSections[y4];
net.minecraft.world.level.block.state.BlockState existing;
if (section == null) {
existing = ((PaperweightBlockMaterial) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
} else {
existing = section.getBlockState(x & 15, y & 15, z & 15);
}
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null;
if (compoundTag != null || existing instanceof TileEntityBlock) {
level.setBlock(blockPos, blockState, 0);
// remove tile
if (compoundTag != null) {
// We will assume that the tile entity was created for us,
// though we do not do this on the Forge version
BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag);
tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z));
blockEntity.load(tag); // readTagIntoTileEntity - load data
}
}
} else {
if (existing == blockState) {
return true;
}
levelChunk.setBlockState(blockPos, blockState, false);
}
if (update) {
level.getMinecraftWorld().sendBlockUpdated(blockPos, existing, blockState, 0);
}
return true;
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess(
this,
new WeakReference<>(((CraftWorld) world).getHandle())
);
}
@Override
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
CraftEntity craftEntity = ((CraftEntity) entity);
Entity mcEntity = craftEntity.getHandle();
String id = getEntityId(mcEntity);
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
final Map<String, BinaryTag> tags = new HashMap<>();
tag.keySet().forEach(key -> tags.put(key, tag.get(key)));
tags.put("Id", StringBinaryTag.of(id));
return CompoundBinaryTag.from(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
return null;
}
}
@Override
public Component getRichBlockName(BlockType blockType) {
return parent.getRichBlockName(blockType);
}
@Override
public Component getRichItemName(ItemType itemType) {
return parent.getRichItemName(itemType);
}
@Override
public Component getRichItemName(BaseItemStack itemStack) {
return parent.getRichItemName(itemStack);
}
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState();
return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState));
}
@Override
public BlockState adapt(BlockData blockData) {
CraftBlockData cbd = ((CraftBlockData) blockData);
net.minecraft.world.level.block.state.BlockState ibd = cbd.getState();
return adapt(ibd);
}
public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
return BlockTypesCache.states[adaptToChar(blockState)];
}
public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) {
int id = Block.BLOCK_STATE_REGISTRY.getId(blockState);
if (initialised) {
return ibdToStateOrdinal[id];
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal[id];
}
try {
init();
return ibdToStateOrdinal[id];
} catch (ArrayIndexOutOfBoundsException e1) {
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
);
return BlockTypesCache.ReservedIDs.AIR;
}
}
}
public char ibdIDToOrdinal(int id) {
if (initialised) {
return ibdToStateOrdinal[id];
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal[id];
}
init();
return ibdToStateOrdinal[id];
}
}
@Override
public char[] getIbdToStateOrdinal() {
if (initialised) {
return ibdToStateOrdinal;
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal;
}
init();
return ibdToStateOrdinal;
}
}
public int ordinalToIbdID(char ordinal) {
if (initialised) {
return ordinalToIbdID[ordinal];
}
synchronized (this) {
if (initialised) {
return ordinalToIbdID[ordinal];
}
init();
return ordinalToIbdID[ordinal];
}
}
@Override
public int[] getOrdinalToIbdID() {
if (initialised) {
return ordinalToIbdID;
}
synchronized (this) {
if (initialised) {
return ordinalToIbdID;
}
init();
return ordinalToIbdID;
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
return material.getCraftBlockData();
}
@Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) {
ServerLevel nmsWorld = ((CraftWorld) world).getHandle();
ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && map.wasAccessibleSinceLastSave()) {
boolean flag = false;
// PlayerChunk.d players = map.players;
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
*/ Stream.empty();
ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
.forEach(entityPlayer -> {
synchronized (chunkPacket) {
ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket();
if (nmsPacket == null) {
nmsPacket = mapUtil.create(this, chunkPacket);
chunkPacket.setNativePacket(nmsPacket);
}
try {
FaweCache.INSTANCE.CHUNK_FLAG.get().set(true);
entityPlayer.connection.send(nmsPacket);
} finally {
FaweCache.INSTANCE.CHUNK_FLAG.get().set(false);
}
}
});
}
}
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
return getParent().getProperties(blockType);
}
@Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess(
((CraftWorld) world).getHandle(),
new BlockPos(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ())
);
}
@Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
ItemStack stack = new ItemStack(
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())),
baseItemStack.getAmount()
);
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
return CraftItemStack.asCraftMirror(stack);
}
@Override
public boolean generateTree(
TreeGenerator.TreeType treeType, EditSession editSession, BlockVector3 blockVector3,
org.bukkit.World bukkitWorld
) {
TreeType bukkitType = BukkitWorld.toBukkitTreeType(treeType);
if (bukkitType == TreeType.CHORUS_PLANT) {
blockVector3 = blockVector3.add(
0,
1,
0
); // bukkit skips the feature gen which does this offset normally, so we have to add it back
}
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true;
boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType);
serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear();
return false;
} else {
for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue;
}
editSession.setBlock(craftBlockState.getX(), craftBlockState.getY(), craftBlockState.getZ(),
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
);
}
serverLevel.capturedBlockStates.clear();
return true;
}
}
@Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {
// Quickly add each entity to a list copy.
List<Entity> mcEntities = new ArrayList<>();
((CraftWorld) world).getHandle().entityManager.getEntityGetter().getAll().forEach(mcEntities::add);
List<org.bukkit.entity.Entity> list = new ArrayList<>();
mcEntities.forEach((mcEnt) -> {
org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity();
if (bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
});
return list;
}
@Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag())));
return weStack;
}
@Override
public Tag toNative(net.minecraft.nbt.Tag foreign) {
return parent.toNative(foreign);
}
@Override
public net.minecraft.nbt.Tag fromNative(Tag foreign) {
if (foreign instanceof PaperweightLazyCompoundTag) {
return ((PaperweightLazyCompoundTag) foreign).get();
}
return parent.fromNative(foreign);
}
@Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
return new PaperweightRegen(bukkitWorld, region, target, options).regenerate();
}
@Override
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
return new PaperweightGetBlocks(world, chunkX, chunkZ);
}
@Override
public int getInternalBiomeId(BiomeType biomeType) {
if (biomeType.getId().startsWith("minecraft:")) {
Biome biomeBase = CraftBlock.biomeToBiomeBase(
MinecraftServer.getServer().registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY),
BukkitAdapter.adapt(biomeType)
);
return MinecraftServer.getServer().registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biomeBase);
} else {
WritableRegistry<Biome> biomeRegistry = MinecraftServer.getServer().registryAccess()
.ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
ResourceLocation resourceLocation = biomeRegistry.keySet().stream()
.filter(resource -> resource.toString().equals(biomeType.getId()))
.findAny().orElse(null);
return biomeRegistry.getId(biomeRegistry.get(resourceLocation));
}
}
@Override
public Iterable<NamespacedKey> getRegisteredBiomes() {
WritableRegistry<Biome> biomeRegistry = ((CraftServer) Bukkit.getServer())
.getServer()
.registryAccess()
.ownedRegistryOrThrow(
Registry.BIOME_REGISTRY);
return biomeRegistry.stream()
.map(biomeRegistry::getKey)
.map(CraftNamespacedKey::fromMinecraft)
.collect(Collectors.toList());
}
@Override
public RelighterFactory getRelighterFactory() {
try {
Class.forName("ca.spottedleaf.starlight.common.light.StarLightEngine");
if (PaperweightStarlightRelighter.isUsable()) {
return new PaperweightStarlightRelighterFactory();
}
} catch (ThreadDeath td) {
throw td;
} catch (Throwable ignored) {
}
return new NMSRelighterFactory();
}
@Override
public Map<String, List<Property<?>>> getAllProperties() {
if (initialised) {
return allBlockProperties;
}
synchronized (this) {
if (initialised) {
return allBlockProperties;
}
init();
return allBlockProperties;
}
}
}

View File

@ -0,0 +1,286 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.util.TaskManager;
import com.fastasyncworldedit.core.util.task.RunnableVal;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<LevelChunk,
net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private static final Direction[] NEIGHBOUR_ORDER = {
Direction.EAST,
Direction.WEST,
Direction.DOWN,
Direction.UP,
Direction.NORTH,
Direction.SOUTH
};
private final PaperweightFaweAdapter paperweightFaweAdapter;
private final WeakReference<Level> level;
private final AtomicInteger lastTick;
private final Set<CachedChange> cachedChanges = new HashSet<>();
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
private SideEffectSet sideEffectSet;
public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference<Level> level) {
this.paperweightFaweAdapter = paperweightFaweAdapter;
this.level = level;
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
}
private Level getLevel() {
return Objects.requireNonNull(level.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getLevel().getChunk(x, z);
}
@Override
public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) {
int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState();
}
@Override
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) {
return levelChunk.getBlockState(blockPos);
}
@Nullable
@Override
public synchronized net.minecraft.world.level.block.state.BlockState setBlockState(
LevelChunk levelChunk, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
int currentTick = MinecraftServer.currentTick;
if (Fawe.isMainThread()) {
return levelChunk.setBlockState(blockPos, blockState,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE)
);
}
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
cachedChunksToSend.add(new IntPair(levelChunk.bukkitChunk.getX(), levelChunk.bukkitChunk.getZ()));
boolean nextTick = lastTick.get() > currentTick;
if (nextTick || cachedChanges.size() >= 1024) {
if (nextTick) {
lastTick.set(currentTick);
}
flushAsync(nextTick);
}
return blockState;
}
@Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(
net.minecraft.world.level.block.state.BlockState blockState,
BlockPos blockPos
) {
return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos blockPos) {
getLevel().getChunkSource().getLightEngine().checkBlock(blockPos);
}
@Override
public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) {
// We will assume that the tile entity was created for us,
// though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) {
return false;
}
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag);
blockEntity.load((CompoundTag) nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(
LevelChunk levelChunk, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk levelChunk) {
return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING);
}
@Override
public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) {
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos);
}
}
@Override
public void notifyNeighbors(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
Level level = getLevel();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
level.blockUpdated(blockPos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
// Un-nest neighbour updating
for (Direction direction : NEIGHBOUR_ORDER) {
BlockPos shifted = blockPos.relative(direction);
level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false);
}
}
if (newState.hasAnalogOutputSignal()) {
level.updateNeighbourForOutputSignal(blockPos, newState.getBlock());
}
}
@Override
public void updateNeighbors(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState,
int recursionLimit
) {
Level level = getLevel();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = level.getWorld();
if (craftWorld != null) {
BlockPhysicsEvent event = new BlockPhysicsEvent(
craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()),
CraftBlockData.fromData(newState)
);
level.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
}
newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
getLevel().onBlockStateChange(blockPos, oldState, newState);
}
private synchronized void flushAsync(final boolean sendChunks) {
final Set<CachedChange> changes = Set.copyOf(cachedChanges);
cachedChanges.clear();
final Set<IntPair> toSend;
if (sendChunks) {
toSend = Set.copyOf(cachedChunksToSend);
cachedChunksToSend.clear();
} else {
toSend = Collections.emptySet();
}
RunnableVal<Object> runnableVal = new RunnableVal<>() {
@Override
public void run(Object value) {
changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
));
if (!sendChunks) {
return;
}
for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
}
}
};
TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
}
@Override
public synchronized void flush() {
RunnableVal<Object> runnableVal = new RunnableVal<>() {
@Override
public void run(Object value) {
cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
));
for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
}
}
};
if (Fawe.isMainThread()) {
runnableVal.run();
} else {
TaskManager.taskManager().sync(runnableVal);
}
cachedChanges.clear();
cachedChunksToSend.clear();
}
private record CachedChange(
LevelChunk levelChunk,
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
}
}

View File

@ -0,0 +1,240 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
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.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.PalettedContainer;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
private final ServerLevel serverLevel;
private PalettedContainer<Biome>[] biomes = null;
protected PaperweightGetBlocks_Copy(ServerLevel world) {
this.serverLevel = world;
this.minHeight = world.getMinBuildHeight();
this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
}
protected void storeTile(BlockEntity blockEntity) {
tiles.put(
BlockVector3.at(
blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ()
),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
);
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag)));
}
@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 boolean isCreateCopy() {
return false;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setHeightmapToGet(HeightMapType type, int[] data) {
}
@Override
public int getMaxY() {
return maxHeight;
}
@Override
public int getMinY() {
return minHeight;
}
@Override
public int getMaxSectionPosition() {
return maxHeight >> 4;
}
@Override
public int getMinSectionPosition() {
return minHeight >> 4;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Biome biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
return biome != null ? PaperweightPlatformAdapter.adapt(biome, serverLevel) : 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;
}
@Override
public int getSectionCount() {
return serverLevel.getSectionsCount();
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
protected void storeBiomes(int layer, PalettedContainer<Biome> biomeData) {
if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()];
}
biomes[layer] = biomeData;
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(int layer) {
layer -= getMinSectionPosition();
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public char[] loadIfPresent(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = (y >> 4) - getMinSectionPosition();
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -0,0 +1,35 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
//TODO un-very-break-this
public class PaperweightMapChunkUtil extends MapChunkUtil<ClientboundLevelChunkWithLightPacket> {
public PaperweightMapChunkUtil() throws NoSuchFieldException {
fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a"));
fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a"));
fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b"));
fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b"));
fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c"));
fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c"));
fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d"));
fieldX.setAccessible(true);
fieldZ.setAccessible(true);
fieldBitMask.setAccessible(true);
fieldHeightMap.setAccessible(true);
fieldChunkData.setAccessible(true);
fieldBlockEntities.setAccessible(true);
fieldFull.setAccessible(true);
}
@Override
public ClientboundLevelChunkWithLightPacket createPacket() {
// TODO ??? return new ClientboundLevelChunkPacket();
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,661 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.BitStorage;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector;
import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.gameevent.GameEventDispatcher;
import net.minecraft.world.level.gameevent.GameEventListener;
import org.bukkit.craftbukkit.v1_18_R1.CraftChunk;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.function.Function;
public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldData;
public static final Constructor<?> dataConstructor;
public static final Field fieldStorage;
public static final Field fieldPalette;
public static final Field fieldTickingFluidCount;
public static final Field fieldTickingBlockCount;
public static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock;
private static final long fieldLockOffset;
private static final Field fieldGameEventDispatcherSections;
private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldRemove;
static {
try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
fieldData.setAccessible(true);
Class<?> dataClazz = fieldData.getType();
dataConstructor = dataClazz.getDeclaredConstructors()[0];
dataConstructor.setAccessible(true);
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
fieldStorage.setAccessible(true);
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
fieldNonEmptyBlockCount.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent",
"b"
), long.class);
getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
"gameEventDispatcherSections", "t"));
fieldGameEventDispatcherSections.setAccessible(true);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName(
"removeBlockEntityTicker",
"m"
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (RuntimeException e) {
throw e;
} catch (Throwable rethrow) {
rethrow.printStackTrace();
throw new RuntimeException(rethrow);
}
}
static boolean setSectionAtomic(
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
}
static DelegateSemaphore applyLock(LevelChunkSection section) {
try {
synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(blocks,
fieldThreadingDetectorOffset) ;
synchronized(currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore) {
return (DelegateSemaphore) currentLock;
}
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);
return newLock;
}
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
return nmsChunk;
}
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
return nmsChunk;
}
// Avoid "async" methods from the main thread.
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try {
CraftChunk chunk = (CraftChunk) future.get();
return chunk.getHandle();
} catch (Throwable e) {
e.printStackTrace();
}
}
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try {
return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ));
} catch (Throwable thr) {
throw new RuntimeException(thr);
}
}
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) {
return;
}
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
// UNLOADED_CHUNK
Optional<LevelChunk> optional = ((Either) chunkHolder
.getTickingChunkFuture()
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
if (PaperLib.isPaper()) {
// getChunkAtIfLoadedImmediately is paper only
optional = optional.or(() -> Optional.ofNullable(nmsWorld
.getChunkSource()
.getChunkAtIfLoadedImmediately(chunkX, chunkZ)));
}
if (optional.isEmpty()) {
return;
}
LevelChunk levelChunk = optional.get();
TaskManager.taskManager().task(() -> {
ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true,
false // last false is to not bother with x-ray
);
} else {
// deprecated on paper
//noinspection deprecation
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true
);
}
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
});
}
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
}
/*
NMS conversion
*/
public static LevelChunkSection newChunkSection(
final int layer, final char[] blocks, boolean fastmode,
CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Biome> biomes
) {
return newChunkSection(layer, null, blocks, fastmode, adapter, biomeRegistry, biomes);
}
public static LevelChunkSection newChunkSection(
final int layer, final Function<Integer, char[]> get, char[] set,
boolean fastmode, CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Biome> biomes
) {
if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes);
}
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try {
int[] num_palette_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, adapter
);
} else {
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
num_palette_buffer, get, set, ticking_blocks, fastmode, adapter
);
}
int num_palette = num_palette_buffer[0];
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
Object configuration =
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(new FakeIdMapBlock(num_palette), bitsPerEntry);
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
bitsPerEntry = 4;
} else if (bitsPerEntry > 8) {
bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) {
blockStates[i] = 0;
}
} else {
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates);
bitArray.fromRaw(blocksCopy);
}
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
final BitStorage nmsBits;
if (bitsPerEntry == 0) {
nmsBits = new ZeroBitStorage(4096);
} else {
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
}
final Palette<net.minecraft.world.level.block.state.BlockState> blockStatePalette;
List<net.minecraft.world.level.block.state.BlockState> palette;
if (bitsPerEntry < 9) {
palette = new ArrayList<>();
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
final BlockState state = BlockTypesCache.states[ordinal];
palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState());
}
} else {
palette = List.of();
}
// Create palette with data
@SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blockStatePalettedContainer =
new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
PalettedContainer.Strategy.SECTION_STATES,
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry),
nmsBits,
palette
);
LevelChunkSection levelChunkSection;
try {
//fieldStorage.set(dataPaletteBlocks, nmsBits);
//fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
if (biomes == null) {
biomes = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.getOrThrow(Biomes.PLAINS),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
}
levelChunkSection = new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
setCount(ticking_blocks.size(), 4096 - air, levelChunkSection);
if (!fastmode) {
ticking_blocks.forEach((pos, ordinal) -> levelChunkSection.setBlockState(
pos.getBlockX(),
pos.getBlockY(),
pos.getBlockZ(),
Block.stateById(ordinal)
));
}
} catch (final IllegalAccessException e) {
throw new RuntimeException(e);
}
return levelChunkSection;
} catch (final Throwable e) {
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
throw e;
}
}
private static LevelChunkSection newChunkSection(
int layer, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Biome> biomes
) {
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES,
null
);
PalettedContainer<Biome> biomesPalette = biomes != null ? biomes : new PalettedContainer<>(
biomeRegistry,
biomeRegistry.getOrThrow(Biomes.PLAINS),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
return new LevelChunkSection(layer, dataPaletteBlocks, biomesPalette);
}
/**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/
public static PalettedContainer<Biome> getBiomePalettedContainer(BiomeType[] biomes, Registry<Biome> biomeRegistry) {
if (biomes == null) {
return null;
}
// Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length
Map<BiomeType, Biome> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Biome biome;
if (biomeType == null) {
biome = biomeRegistry.getOrThrow(Biomes.PLAINS);
} else {
biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()));
}
palette.put(biomeType, biome);
}
int biomeCount = palette.size();
int bitsPerEntry = MathMan.log2nlz(biomeCount - 1);
Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration(
new FakeIdMapBiome(biomeCount),
bitsPerEntry
);
if (bitsPerEntry > 3) {
bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1);
}
PalettedContainer<Biome> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.getOrThrow(Biomes.PLAINS),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
final Palette<Biome> biomePalette;
if (bitsPerEntry == 0) {
biomePalette = new SingleValuePalette<>(
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry == 4) {
biomePalette = LinearPalette.create(
4,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry < 9) {
biomePalette = HashMapPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else {
biomePalette = GlobalPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
null // unused
);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int arrayLength = MathMan.ceilZero(64f / blocksPerLong);
BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage(
bitsPerEntry,
64,
new long[arrayLength]
);
try {
Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette);
fieldData.set(biomePalettedContainer, data);
int index = 0;
for (int y = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = biomes[index];
if (biomeType == null) {
continue;
}
Biome biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()));
if (biome == null) {
continue;
}
biomePalettedContainer.set(x, y, z, biome);
}
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return biomePalettedContainer;
}
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
IllegalAccessException {
fieldTickingFluidCount.setShort(section, (short) 0); // TODO FIXME
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
}
public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) {
ResourceLocation resourceLocation = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getKey(
biome);
if (resourceLocation == null) {
return levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biome) == -1
? BiomeTypes.OCEAN
: null;
}
return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT));
}
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try {
// Do the method ourselves to avoid trying to reflect generic method parameters
// similar to removeGameEventListener
if (levelChunk.loaded || levelChunk.level.isClientSide()) {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) {
if (!levelChunk.level.isClientSide) {
Block block = beacon.getBlockState().getBlock();
if (block instanceof EntityBlock) {
GameEventListener gameEventListener = ((EntityBlock) block).getListener(levelChunk.level, beacon);
if (gameEventListener != null) {
int i = SectionPos.blockToSectionCoord(beacon.getBlockPos().getY());
GameEventDispatcher gameEventDispatcher = levelChunk.getEventDispatcher(i);
gameEventDispatcher.unregister(gameEventListener);
if (gameEventDispatcher.isEmpty()) {
try {
((Int2ObjectMap<GameEventDispatcher>) fieldGameEventDispatcherSections.get(levelChunk))
.remove(i);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
fieldRemove.set(beacon, true);
}
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static class FakeIdMapBlock implements IdMap<net.minecraft.world.level.block.state.BlockState> {
private final int size;
FakeIdMapBlock(int size) {
this.size = size;
}
@Override
public int getId(final net.minecraft.world.level.block.state.BlockState entry) {
return 0;
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState byId(final int index) {
return null;
}
@Override
public int size() {
return size;
}
@NotNull
@Override
public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator();
}
}
static class FakeIdMapBiome implements IdMap<Biome> {
private final int size;
FakeIdMapBiome(int size) {
this.size = size;
}
@Override
public int getId(final Biome entry) {
return 0;
}
@Nullable
@Override
public Biome byId(final int index) {
return null;
}
@Override
public int size() {
return size;
}
@NotNull
@Override
public Iterator<Biome> iterator() {
return Collections.emptyIterator();
}
}
}

View File

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

View File

@ -0,0 +1,27 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import javax.annotation.Nonnull;
public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override
public @Nonnull
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) {
return NullRelighter.INSTANCE;
}
return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue);
}
}

View File

@ -0,0 +1,158 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import net.minecraft.nbt.NumericTag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class PaperweightLazyCompoundTag extends LazyCompoundTag {
private final Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier;
private CompoundTag compoundTag;
public PaperweightLazyCompoundTag(Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier) {
super(new HashMap<>());
this.compoundTagSupplier = compoundTagSupplier;
}
public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) {
this(() -> compoundTag);
}
public net.minecraft.nbt.CompoundTag get() {
return compoundTagSupplier.get();
}
@Override
public Map<String, Tag> getValue() {
if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
}
return compoundTag.getValue();
}
@Override
public CompoundBinaryTag asBinaryTag() {
getValue();
return compoundTag.asBinaryTag();
}
public boolean containsKey(String key) {
return compoundTagSupplier.get().contains(key);
}
public byte[] getByteArray(String key) {
return compoundTagSupplier.get().getByteArray(key);
}
public byte getByte(String key) {
return compoundTagSupplier.get().getByte(key);
}
public double getDouble(String key) {
return compoundTagSupplier.get().getDouble(key);
}
public double asDouble(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsDouble();
}
return 0;
}
public float getFloat(String key) {
return compoundTagSupplier.get().getFloat(key);
}
public int[] getIntArray(String key) {
return compoundTagSupplier.get().getIntArray(key);
}
public int getInt(String key) {
return compoundTagSupplier.get().getInt(key);
}
public int asInt(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsInt();
}
return 0;
}
public List<Tag> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag> list = new ArrayList<>();
for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag));
} else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
}
}
return list;
}
return Collections.emptyList();
}
public ListTag getListTag(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag) {
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
}
return new ListTag(StringTag.class, Collections.emptyList());
}
@SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue();
} else {
return Collections.emptyList();
}
}
public long[] getLongArray(String key) {
return compoundTagSupplier.get().getLongArray(key);
}
public long getLong(String key) {
return compoundTagSupplier.get().getLong(key);
}
public long asLong(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsLong();
}
return 0;
}
public short getShort(String key) {
return compoundTagSupplier.get().getShort(key);
}
public String getString(String key) {
return compoundTagSupplier.get().getString(key);
}
@Override
public String toString() {
return compoundTagSupplier.get().toString();
}
}

View File

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

View File

@ -42,12 +42,6 @@ repositories {
flatDir { dir(File("src/main/resources")) }
}
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
val localImplementation = configurations.create("localImplementation") {
description = "Dependencies used locally, but provided by the runtime Bukkit implementation"
isCanBeConsumed = false
@ -108,7 +102,6 @@ dependencies {
compileOnly(libs.protocollib) { isTransitive = false }
compileOnly(libs.plotsquaredV6Bukkit) { isTransitive = false }
compileOnly(libs.plotsquaredV6Core) { isTransitive = false }
compileOnly(libs.plotsquaredV4) { isTransitive = false }
// Third party
compileOnly(libs.flowmath) {
@ -187,7 +180,7 @@ tasks.named<ShadowJar>("shadowJar") {
include(dependency("dev.notmyfault.serverlib:ServerLib:2.3.1"))
}
relocate("com.intellectualsites.paster", "com.fastasyncworldedit.paster") {
include(dependency("com.intellectualsites.paster:Paster:1.1.1"))
include(dependency("com.intellectualsites.paster:Paster:1.1.3"))
}
relocate("org.lz4", "com.fastasyncworldedit.core.lz4") {
include(dependency("org.lz4:lz4-java:1.8.0"))

View File

@ -68,7 +68,6 @@ public class FaweBukkit implements IFawe, Listener {
public FaweBukkit(Plugin plugin) {
this.plugin = plugin;
try {
Settings.IMP.TICK_LIMITER.ENABLED = !Bukkit.hasWhitelist();
Fawe.set(this);
Fawe.setupInjector();
try {
@ -76,7 +75,7 @@ public class FaweBukkit implements IFawe, Listener {
} catch (Throwable e) {
LOGGER.error("Brush Listener Failed", e);
}
if (PaperLib.isPaper() && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
if (PaperLib.isPaper() && Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
new RenderListener(plugin);
}
} catch (final Throwable e) {
@ -84,17 +83,19 @@ public class FaweBukkit implements IFawe, Listener {
Bukkit.getServer().shutdown();
}
chunksStretched = new MinecraftVersion().isEqualOrHigher(MinecraftVersion.NETHER);
MinecraftVersion version = new MinecraftVersion();
chunksStretched = version.isEqualOrHigherThan(MinecraftVersion.NETHER);
platformAdapter = new NMSAdapter();
//PlotSquared support is limited to Spigot/Paper as of 02/20/2020
TaskManager.IMP.later(this::setupPlotSquared, 0);
TaskManager.taskManager().later(this::setupPlotSquared, 0);
// Registered delayed Event Listeners
TaskManager.IMP.task(() -> {
TaskManager.taskManager().task(() -> {
// Fix for ProtocolSupport
Settings.IMP.PROTOCOL_SUPPORT_FIX =
Settings.settings().PROTOCOL_SUPPORT_FIX =
Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
// This class
@ -103,6 +104,11 @@ public class FaweBukkit implements IFawe, Listener {
// The tick limiter
new ChunkListener9();
});
// Warn if small-edits are enabled with extended world heights
if (version.isEqualOrHigherThan(MinecraftVersion.CAVES_18) && Settings.settings().HISTORY.SMALL_EDITS) {
LOGGER.warn("Small-edits enabled (maximum y range of 0 -> 256) with 1.18 world heights. Are you sure?");
}
}
@Override
@ -141,7 +147,7 @@ public class FaweBukkit implements IFawe, Listener {
try {
this.itemUtil = tmp = new ItemUtil();
} catch (Throwable e) {
Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES = false;
Settings.settings().EXPERIMENTAL.PERSISTENT_BRUSHES = false;
LOGGER.error("Persistent Brushes Failed", e);
}
}
@ -310,14 +316,12 @@ public class FaweBukkit implements IFawe, Listener {
if (plotSquared == null) {
return;
}
if (plotSquared.getClass().getPackage().toString().contains("intellectualsites")) {
WEManager.IMP.addManager(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.addManager(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
if (PlotSquared.get().getVersion().version[0] == 6) {
WEManager.weManager().addManager(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
LOGGER.info("Plugin 'PlotSquared' v6 found. Using it now.");
} else {
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
LOGGER.info("https://www.spigotmc.org/resources/77506/");
}
}

View File

@ -389,7 +389,7 @@ public interface IBukkitAdapter {
* @return list of {@link org.bukkit.entity.Entity}
*/
default List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {
return TaskManager.IMP.sync(world::getEntities);
return TaskManager.taskManager().sync(world::getEntities);
}
}

View File

@ -59,7 +59,7 @@ public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
}
@Override
default BaseBlock getBlock(Location location) {
default BlockState getBlock(Location location) {
return getParent().getBlock(location);
}

View File

@ -4,7 +4,6 @@ import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.world.block.BlockID;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
@ -24,8 +23,8 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
int num_palette = 0;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
if (ordinal == BlockID.__RESERVED__) {
ordinal = BlockID.AIR;
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
ordinal = BlockTypesCache.ReservedIDs.AIR;
}
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
@ -43,17 +42,15 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
}
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
}
char lastOrdinal = BlockID.__RESERVED__;
char lastOrdinal = 0;
boolean lastticking = false;
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
case BlockID.__RESERVED__:
ordinal = BlockID.AIR;
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
case BlockTypesCache.ReservedIDs.__RESERVED__:
ordinal = BlockTypesCache.ReservedIDs.AIR;
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR:
air++;
break;
default:
@ -95,13 +92,13 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
char[] getArr = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
if (ordinal == BlockID.__RESERVED__) {
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (getArr == null) {
getArr = get.apply(layer);
}
ordinal = getArr[i];
if (ordinal == BlockID.__RESERVED__) {
ordinal = BlockID.AIR;
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
ordinal = BlockTypesCache.ReservedIDs.AIR;
}
}
int palette = blockToPalette[ordinal];
@ -120,26 +117,23 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
}
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
}
char lastOrdinal = BlockID.__RESERVED__;
char lastOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean lastticking = false;
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
boolean tick_existing = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_EXISTING;
boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED;
boolean tick_existing = Settings.settings().EXPERIMENTAL.ALLOW_TICK_EXISTING;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
case BlockID.__RESERVED__: {
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
if (getArr == null) {
getArr = get.apply(layer);
}
ordinal = getArr[i];
switch (ordinal) {
case BlockID.__RESERVED__:
ordinal = BlockID.AIR;
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
set[i] = switch (ordinal = getArr[i]) {
case BlockTypesCache.ReservedIDs.__RESERVED__:
ordinal = BlockTypesCache.ReservedIDs.AIR;
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR:
air++;
break;
yield ordinal;
default:
if (!fastmode && !tick_placed && tick_existing) {
boolean ticking;
@ -152,23 +146,19 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
}
if (ticking) {
BlockState state = BlockState.getFromOrdinal(ordinal);
ticking_blocks
.put(
BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin.getInstance().getBukkitImplAdapter()
.getInternalBlockStateId(state).orElse(0)
);
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBlockStateId(state)
.orElse(0)
);
}
}
}
set[i] = ordinal;
break;
yield ordinal;
};
}
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
air++;
break;
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> air++;
}
if (!fastmode && tick_placed) {
boolean ticking;

View File

@ -18,7 +18,7 @@ public class NMSRelighterFactory implements RelighterFactory {
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
return new NMSRelighter(
queue,
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE)
relightMode != null ? relightMode : RelightMode.valueOf(Settings.settings().LIGHTING.MODE)
);
}

View File

@ -5,7 +5,10 @@ import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
import com.fastasyncworldedit.core.util.MathMan;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
@ -32,6 +35,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -151,7 +155,10 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
private boolean generate() throws Exception {
if (generateConcurrent) {
//Using concurrent chunk generation
executor = Executors.newFixedThreadPool(Settings.IMP.QUEUE.PARALLEL_THREADS);
executor = Executors.newFixedThreadPool(Settings.settings().QUEUE.PARALLEL_THREADS, new ThreadFactoryBuilder()
.setNameFormat("fawe-regen-%d")
.build()
);
} // else using sequential chunk generation, concurrent not supported
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
@ -283,19 +290,52 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
private void copyToWorld() {
//Setting Blocks
long start = System.currentTimeMillis();
boolean genbiomes = options.shouldRegenBiomes();
boolean hasBiome = options.hasBiomeType();
BiomeType biome = options.getBiomeType();
for (BlockVector3 vec : region) {
BaseBlock block = source.getFullBlock(vec);
target.setBlock(vec, block);
if (hasBiome) {
target.setBiome(vec, biome);
} else if (genbiomes) {
target.setBiome(vec, source.getBiome(vec));
}
if (!genbiomes && !hasBiome) {
target.setBlocks(region, new PlacementPattern());
}
if (hasBiome) {
target.setBlocks(region, new WithBiomePlacementPattern(ignored -> biome));
} else if (genbiomes) {
target.setBlocks(region, new WithBiomePlacementPattern(vec -> source.getBiome(vec)));
}
}
private class PlacementPattern implements Pattern {
@Override
public BaseBlock applyBlock(final BlockVector3 position) {
return source.getFullBlock(position);
}
@Override
public boolean apply(final Extent extent, final BlockVector3 get, final BlockVector3 set) throws WorldEditException {
return extent.setBlock(set.getX(), set.getY(), set.getZ(), source.getFullBlock(get.getX(), get.getY(), get.getZ()));
}
}
private class WithBiomePlacementPattern implements Pattern {
private final Function<BlockVector3, BiomeType> biomeGetter;
private WithBiomePlacementPattern(final Function<BlockVector3, BiomeType> biomeGetter) {
this.biomeGetter = biomeGetter;
}
@Override
public BaseBlock applyBlock(final BlockVector3 position) {
return source.getFullBlock(position);
}
@Override
public boolean apply(final Extent extent, final BlockVector3 get, final BlockVector3 set) throws WorldEditException {
return extent.setBlock(set.getX(), set.getY(), set.getZ(), source.getFullBlock(get.getX(), get.getY(), get.getZ()))
&& extent.setBiome(set.getX(), set.getY(), set.getZ(), biomeGetter.apply(get));
}
}
//functions to be implemented by sub class

View File

@ -45,20 +45,25 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.util.Vector;
/**
* @deprecated FAWE is not necessarily the tool you want to use to limit certain tick actions, e.g. fireworks or elytra flying.
* The code is untouched since the 1.12 era and there is no guarantee that it will work or will be maintained in the future.
*/
@Deprecated(since = "2.0.0")
public abstract class ChunkListener implements Listener {
private static final Logger LOGGER = LogManagerCompat.getLogger();
protected int rateLimit = 0;
protected Location lastCancelPos;
private final int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS,
Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
private final int[] badLimit = new int[]{Settings.settings().TICK_LIMITER.PHYSICS_MS,
Settings.settings().TICK_LIMITER.FALLING, Settings.settings().TICK_LIMITER.ITEMS};
public ChunkListener() {
if (Settings.IMP.TICK_LIMITER.ENABLED) {
if (Settings.settings().TICK_LIMITER.ENABLED) {
PluginManager plm = Bukkit.getPluginManager();
Plugin plugin = Fawe.<FaweBukkit>imp().getPlugin();
Plugin plugin = Fawe.<FaweBukkit>platform().getPlugin();
plm.registerEvents(this, plugin);
TaskManager.IMP.repeat(() -> {
TaskManager.taskManager().repeat(() -> {
Location tmpLoc = lastCancelPos;
if (tmpLoc != null) {
LOGGER.info("[FAWE Tick Limiter] Detected and cancelled physics lag source at {}", tmpLoc);
@ -80,7 +85,7 @@ public abstract class ChunkListener implements Listener {
counter.put(key, badLimit);
}
badChunks.clear();
}, Settings.IMP.TICK_LIMITER.INTERVAL);
}, Settings.settings().TICK_LIMITER.INTERVAL);
}
}
@ -88,7 +93,15 @@ public abstract class ChunkListener implements Listener {
protected abstract StackTraceElement getElement(Exception ex, int index);
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public static boolean physicsFreeze = false;
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public static boolean itemFreeze = false;
protected final Long2ObjectOpenHashMap<Boolean> badChunks = new Long2ObjectOpenHashMap<>();
@ -97,6 +110,10 @@ public abstract class ChunkListener implements Listener {
private int lastZ = Integer.MIN_VALUE;
private int[] lastCount;
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public int[] getCount(int cx, int cz) {
if (lastX == cx && lastZ == cz) {
return lastCount;
@ -112,6 +129,10 @@ public abstract class ChunkListener implements Listener {
return tmp;
}
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public void cleanup(Chunk chunk) {
for (Entity entity : chunk.getEntities()) {
if (entity.getType() == EntityType.DROPPED_ITEM) {
@ -128,6 +149,10 @@ public abstract class ChunkListener implements Listener {
protected long physStart;
protected long physTick;
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public final void reset() {
physSkip = 0;
physStart = System.currentTimeMillis();
@ -241,13 +266,13 @@ public abstract class ChunkListener implements Listener {
if ((++physSkip & 1023) != 0) {
return;
}
FaweTimer timer = Fawe.get().getTimer();
FaweTimer timer = Fawe.instance().getTimer();
if (timer.getTick() != physTick) {
physTick = timer.getTick();
physStart = System.currentTimeMillis();
return;
} else if (System.currentTimeMillis() - physStart
< Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
< Settings.settings().TICK_LIMITER.PHYSICS_MS) {
return;
}
}
@ -324,15 +349,15 @@ public abstract class ChunkListener implements Listener {
int cx = x >> 4;
int cz = z >> 4;
int[] count = getCount(cx, cz);
if (count[1] >= Settings.IMP.TICK_LIMITER.FALLING) {
if (count[1] >= Settings.settings().TICK_LIMITER.FALLING) {
event.setCancelled(true);
return;
}
if (event.getEntityType() == EntityType.FALLING_BLOCK) {
if (++count[1] >= Settings.IMP.TICK_LIMITER.FALLING) {
if (++count[1] >= Settings.settings().TICK_LIMITER.FALLING) {
// Only cancel falling blocks when it's lagging
if (Fawe.get().getTimer().getTPS() < 18) {
if (Fawe.instance().getTimer().getTPS() < 18) {
cancelNearby(cx, cz);
if (rateLimit <= 0) {
rateLimit = 20;
@ -351,7 +376,7 @@ public abstract class ChunkListener implements Listener {
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onChunkLoad(ChunkLoadEvent event) {
if (!Settings.IMP.TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) {
if (!Settings.settings().TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) {
Chunk chunk = event.getChunk();
Entity[] entities = chunk.getEntities();
World world = chunk.getWorld();
@ -377,8 +402,8 @@ public abstract class ChunkListener implements Listener {
if (Math.abs(velocity.getX()) > vertical
|| Math.abs(velocity.getZ()) > vertical) {
LOGGER.warn(
"[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at "
+ ent.getLocation());
"[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at {}",
ent.getLocation());
ent.remove();
}
}
@ -398,17 +423,17 @@ public abstract class ChunkListener implements Listener {
int cx = loc.getBlockX() >> 4;
int cz = loc.getBlockZ() >> 4;
int[] count = getCount(cx, cz);
if (count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) {
if (count[2] >= Settings.settings().TICK_LIMITER.ITEMS) {
event.setCancelled(true);
return;
}
if (++count[2] >= Settings.IMP.TICK_LIMITER.ITEMS) {
if (++count[2] >= Settings.settings().TICK_LIMITER.ITEMS) {
cleanup(loc.getChunk());
cancelNearby(cx, cz);
if (rateLimit <= 0) {
rateLimit = 20;
LOGGER.warn(
"[FAWE `tick-limiter`] Detected and cancelled item lag source at " + loc);
"[FAWE `tick-limiter`] Detected and cancelled item lag source at {}", loc);
}
event.setCancelled(true);
}

View File

@ -9,11 +9,20 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPhysicsEvent;
/**
* @deprecated FAWE is not necessarily the tool you want to use to limit certain tick actions, e.g. fireworks or elytra flying.
* The code is untouched since the 1.12 era and there is no guarantee that it will work or will be maintained in the future.
*/
@Deprecated(since = "2.0.0")
public class ChunkListener9 extends ChunkListener {
private Exception exception;
private StackTraceElement[] elements;
/**
* @deprecated see {@link com.fastasyncworldedit.bukkit.listener.ChunkListener9} for an explanation of the deprecation
*/
@Deprecated(since = "2.0.0")
public ChunkListener9() {
super();
}
@ -37,13 +46,13 @@ public class ChunkListener9 extends ChunkListener {
event.setCancelled(true);
return;
}
if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
if (System.currentTimeMillis() - physStart > Settings.settings().TICK_LIMITER.PHYSICS_MS) {
physCancelPair = pair;
event.setCancelled(true);
return;
}
}
FaweTimer timer = Fawe.get().getTimer();
FaweTimer timer = Fawe.instance().getTimer();
if (timer.getTick() != physTick) {
physTick = timer.getTick();
physStart = System.currentTimeMillis();
@ -52,7 +61,7 @@ public class ChunkListener9 extends ChunkListener {
return;
}
if ((++physSkip & 1023) == 0) {
if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
if (System.currentTimeMillis() - physStart > Settings.settings().TICK_LIMITER.PHYSICS_MS) {
Block block = event.getBlock();
int cx = block.getX() >> 4;
int cz = block.getZ() >> 4;

View File

@ -28,7 +28,7 @@ public class RenderListener implements Listener {
public RenderListener(Plugin plugin) {
Bukkit.getPluginManager().registerEvents(this, plugin);
TaskManager.IMP.repeat(new Runnable() {
TaskManager.taskManager().repeat(new Runnable() {
private long last = 0;
@Override
@ -38,7 +38,7 @@ public class RenderListener implements Listener {
}
long now = System.currentTimeMillis();
int tps32 = (int) (Math.round(Fawe.get().getTimer().getTPS()) * 32);
int tps32 = (int) (Math.round(Fawe.instance().getTimer().getTPS()) * 32);
long diff = now - last;
last = now;
if (diff > 75) {
@ -56,7 +56,7 @@ public class RenderListener implements Listener {
if (entrySet == null || !entrySet.hasNext()) {
entrySet = views.entrySet().iterator();
}
int nowTick = (int) (Fawe.get().getTimer().getTick());
int nowTick = (int) (Fawe.instance().getTimer().getTick());
while (entrySet.hasNext()) {
Map.Entry<UUID, int[]> entry = entrySet.next();
Player player = Bukkit.getPlayer(entry.getKey());
@ -81,17 +81,17 @@ public class RenderListener implements Listener {
private void setViewDistance(Player player, int value) {
UUID uuid = player.getUniqueId();
if (value == Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) {
if (value == Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) {
views.remove(uuid);
} else {
int[] val = views.get(uuid);
if (val == null) {
val = new int[]{value, (int) Fawe.get().getTimer().getTick()};
val = new int[]{value, (int) Fawe.instance().getTimer().getTick()};
UUID uid = player.getUniqueId();
views.put(uid, val);
} else {
if (value <= val[0]) {
val[1] = (int) Fawe.get().getTimer().getTick();
val[1] = (int) Fawe.instance().getTimer().getTick();
}
if (val[0] == value) {
return;
@ -105,7 +105,7 @@ public class RenderListener implements Listener {
private int getViewDistance(Player player) {
int[] value = views.get(player.getUniqueId());
return value == null ? Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING : value[0];
return value == null ? Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING : value[0];
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)

View File

@ -32,7 +32,7 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener
}
@Override
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) {
final Player player = BukkitAdapter.adapt(wePlayer);
final Location loc = player.getLocation();
final Vector3i vector = Vector3i.from(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());

View File

@ -1,7 +1,9 @@
package com.fastasyncworldedit.bukkit.regions;
import com.fastasyncworldedit.core.regions.FaweMask;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
@ -30,7 +32,7 @@ public class GriefPreventionFeature extends BukkitMaskManager implements Listene
}
@Override
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) {
final Player player = BukkitAdapter.adapt(wePlayer);
final Claim claim = GriefPrevention.instance.dataStore.getClaimAt(player.getLocation(), true, null);
if (claim != null) {
@ -38,12 +40,12 @@ public class GriefPreventionFeature extends BukkitMaskManager implements Listene
claim.getGreaterBoundaryCorner().getBlockX();
final BlockVector3 pos1 = BlockVector3.at(
claim.getLesserBoundaryCorner().getBlockX(),
0,
player.getWorld().getMinHeight(),
claim.getLesserBoundaryCorner().getBlockZ()
);
final BlockVector3 pos2 = BlockVector3.at(
claim.getGreaterBoundaryCorner().getBlockX(),
256,
player.getWorld().getMaxHeight(),
claim.getGreaterBoundaryCorner().getBlockZ()
);
return new FaweMask(new CuboidRegion(pos1, pos2)) {

View File

@ -33,13 +33,13 @@ public class ResidenceFeature extends BukkitMaskManager implements Listener {
return residence != null &&
(residence.getOwner().equals(player.getName()) ||
residence.getOwner().equals(player.getUniqueId().toString()) ||
type == MaskType.MEMBER && TaskManager.IMP.sync(() -> residence
type == MaskType.MEMBER && TaskManager.taskManager().sync(() -> residence
.getPermissions()
.playerHas(player, "build", false)));
}
@Override
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, final MaskType type) {
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, final MaskType type, boolean isWhitelist) {
final Player player = BukkitAdapter.adapt(wePlayer);
final Location location = player.getLocation();
ClaimedResidence residence = Residence.getInstance().getResidenceManager().getByLoc(location);

View File

@ -66,7 +66,7 @@ public class TownyFeature extends BukkitMaskManager implements Listener {
}
@Override
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
public FaweMask getMask(final com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) {
final Player player = BukkitAdapter.adapt(wePlayer);
final Location location = player.getLocation();
try {

View File

@ -53,7 +53,7 @@ public class FaweDelegateRegionManager {
int maxY,
Runnable whenDone
) {
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
World world = BukkitAdapter.adapt(getWorld(area.getWorldName()));
EditSession session = WorldEdit.getInstance().newEditSessionBuilder().world(world).checkMemory(false).
@ -67,14 +67,14 @@ public class FaweDelegateRegionManager {
session.flushQueue();
for (CuboidRegion region : regions) {
FaweAPI.fixLighting(world, region, null,
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE)
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE)
);
}
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
} finally {
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
}
}
@ -92,7 +92,7 @@ public class FaweDelegateRegionManager {
@Nullable Runnable whenDone,
@Nonnull PlotManager manager
) {
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
final HybridPlotWorld hybridPlotWorld = ((HybridPlotManager) manager).getHybridPlotWorld();
World world = BukkitAdapter.adapt(getWorld(hybridPlotWorld.getWorldName()));
@ -176,10 +176,10 @@ public class FaweDelegateRegionManager {
world,
new CuboidRegion(plot.getBottomAbs().getBlockVector3(), plot.getTopAbs().getBlockVector3()),
null,
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE)
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE)
);
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
}
});
@ -192,7 +192,7 @@ public class FaweDelegateRegionManager {
Location swapPos,
final Runnable whenDone
) {
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
//todo because of the following code this should proably be in the Bukkit module
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
@ -220,18 +220,22 @@ public class FaweDelegateRegionManager {
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());
copyA.setCopyingBiomes(true);
copyB.setCopyingBiomes(true);
try {
Operations.completeLegacy(copyA);
Operations.completeLegacy(copyB);
clipA.paste(sessionB, swapPos.getBlockVector3(), true);
clipB.paste(sessionA, pos1.getBlockVector3(), true);
sessionA.flushQueue();
sessionB.flushQueue();
clipA.flush();
clipB.flush();
clipA.paste(sessionB, swapPos.getBlockVector3(), true, true, true);
clipB.paste(sessionA, pos1.getBlockVector3(), true, true, true);
sessionA.close();
sessionB.close();
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null,
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE)
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE)
);
FaweAPI.fixLighting(pos1World, new CuboidRegion(
swapPos.getBlockVector3(),
@ -241,10 +245,10 @@ public class FaweDelegateRegionManager {
swapPos.getZ() + pos2.getZ() - pos1.getZ()
)
), null,
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE)
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE)
);
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
}
});
@ -253,7 +257,7 @@ public class FaweDelegateRegionManager {
public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, String world, Runnable whenDone) {
region.expand(BlockVector3.at(extendBiome, 0, extendBiome));
region.expand(BlockVector3.at(-extendBiome, 0, -extendBiome));
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
EditSession editSession = WorldEdit
.getInstance()
@ -273,7 +277,7 @@ public class FaweDelegateRegionManager {
e.printStackTrace();
}
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
}
});
@ -285,7 +289,7 @@ public class FaweDelegateRegionManager {
final @NonNull Location pos3,
final @NonNull Runnable whenDone
) {
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorldName()));
@ -319,21 +323,21 @@ public class FaweDelegateRegionManager {
pos3.getBlockVector3(),
pos3.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3()))
),
null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE)
null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.settings().LIGHTING.MODE)
);
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
}
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
});
return true;
}
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
synchronized (FaweDelegateRegionManager.class) {
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
try (EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World)
@ -350,7 +354,7 @@ public class FaweDelegateRegionManager {
editSession.flushQueue();
}
if (whenDone != null) {
TaskManager.IMP.task(whenDone);
TaskManager.taskManager().task(whenDone);
}
}
});

View File

@ -132,7 +132,7 @@ public class FaweDelegateSchematicHandler {
}
};
if (Fawe.isMainThread()) {
com.fastasyncworldedit.core.util.TaskManager.IMP.async(r);
com.fastasyncworldedit.core.util.TaskManager.taskManager().async(r);
} else {
r.run();
}
@ -186,7 +186,7 @@ public class FaweDelegateSchematicHandler {
}
return;
}
final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
final CompoundTag weTag = (CompoundTag) FaweCache.INSTANCE.asTag(tag);
SchematicHandler.upload(uuid, file, "schem", new RunnableVal<>() {
@Override
public void run(OutputStream output) {
@ -235,10 +235,8 @@ public class FaweDelegateSchematicHandler {
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e3) {
LOGGER.warn("{} | {} : {}", is, is.getClass().getCanonicalName(), e.getMessage());
e.printStackTrace();
LOGGER.warn(
is + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
.getMessage());
}
}
}

View File

@ -35,8 +35,8 @@ public class FaweQueueCoordinator extends QueueCoordinator {
public FaweQueueCoordinator(World world) {
super(world);
this.world = world;
instance = Fawe.get().getQueueHandler().getQueue(world);
Fawe.get().getQueueHandler().unCache();
instance = Fawe.instance().getQueueHandler().getQueue(world);
Fawe.instance().getQueueHandler().unCache();
}
@Override
@ -194,7 +194,7 @@ public class FaweQueueCoordinator extends QueueCoordinator {
@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));
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.INSTANCE.asTag(tag));
return true;
}

View File

@ -37,7 +37,7 @@ public class FaweTrim extends SubCommand {
return false;
}
ran = true;
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
try {
// TODO NOT IMPLEMENTED
//PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));

View File

@ -89,7 +89,7 @@ public class PlotSetBiome extends Command {
return;
}
plot.addRunning();
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
EditSession session =
WorldEdit
.getInstance()

View File

@ -4,9 +4,6 @@ import com.fastasyncworldedit.core.FaweAPI;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.regions.FaweMask;
import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.regions.filter.RegionFilter;
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.database.DBFunc;
import com.plotsquared.core.player.PlotPlayer;
@ -62,6 +59,15 @@ public class PlotSquaredFeature extends FaweMaskManager {
*/
}
/**
* Whether the player is allowed to use FAWE on a PlotSquared plot.
*
* @param player the {@link Player}
* @param plot the {@link Plot}
* @param type the {@link MaskType}
* @return {@code true} if the player is the plot owner, trusted, has the permission fawe.plotsquared.member
* or fawe.plotsquared.admin and the NoWorldeditFlag is not set; otherwise {@code false}
*/
public boolean isAllowed(Player player, Plot plot, MaskType type) {
if (plot == null) {
return false;
@ -121,7 +127,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
}
@Override
public FaweMask getMask(Player player, MaskType type) {
public FaweMask getMask(Player player, MaskType type, boolean isWhitelist) {
final PlotPlayer<org.bukkit.entity.Player> pp = PlotPlayer.from(BukkitAdapter.adapt(player));
if (pp == null) {
return null;

View File

@ -46,9 +46,9 @@ public class ReplaceAll extends Command {
plot.addRunning();
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
Captions.TASK_START.send(player);
TaskManager.IMP.async(() -> fp.runAction(() -> {
TaskManager.taskManager().async(() -> fp.runAction(() -> {
String worldName = plot.getWorldName();
TaskManager.IMP.sync(new RunnableVal<Object>() {
TaskManager.taskManager().sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
SetupUtils.manager.unload(worldName, true);
@ -58,7 +58,7 @@ public class ReplaceAll extends Command {
String cmd = "/replaceallpattern " + worldName + " " + StringMan.join(args, " ");
CommandEvent event = new CommandEvent(actor, cmd);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
TaskManager.IMP.sync(new RunnableVal<Object>() {
TaskManager.taskManager().sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
plot.teleportPlayer(player);

View File

@ -1,172 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
import com.fastasyncworldedit.core.configuration.Settings;
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;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.World;
import java.util.concurrent.CompletableFuture;
import static org.bukkit.Bukkit.getWorld;
public class FaweChunkManager extends ChunkManager {
private final ChunkManager parent;
public FaweChunkManager(ChunkManager parent) {
this.parent = parent;
}
@Override
public int[] countEntities(Plot plot) {
return parent.countEntities(plot);
}
@Override
public CompletableFuture loadChunk(String world, BlockVector2 loc, boolean force) {
return parent.loadChunk(world, loc, force);
}
@Override
public void unloadChunk(String world, BlockVector2 loc, boolean save) {
parent.unloadChunk(world, loc, save);
}
@Override
public void clearAllEntities(Location pos1, Location pos2) {
parent.clearAllEntities(pos1, pos2);
}
@Override
public void swap(
final Location pos1,
final Location pos2,
final Location pos3,
final Location pos4,
final Runnable whenDone
) {
if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
parent.swap(pos1, pos2, pos3, pos4, whenDone);
}
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.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()));
EditSession sessionA = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.build();
EditSession sessionB = WorldEdit.getInstance().newEditSessionBuilder().world(pos3World)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.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());
try {
Operations.completeLegacy(copyA);
Operations.completeLegacy(copyB);
sessionA.flushQueue();
sessionB.flushQueue();
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
TaskManager.IMP.task(whenDone);
}
});
}
@Override
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
if (!Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
return parent.copyRegion(pos1, pos2, pos3, whenDone);
}
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.class) {
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
EditSession from = WorldEdit.getInstance().newEditSessionBuilder().world(pos1World)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.build();
EditSession to = WorldEdit.getInstance().newEditSessionBuilder().world(pos3World)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.build();
CuboidRegion region = new CuboidRegion(
BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()),
BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ())
);
ForwardExtentCopy copy = new ForwardExtentCopy(
from,
region,
to,
BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ())
);
try {
Operations.completeLegacy(copy);
to.flushQueue();
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
}
TaskManager.IMP.task(whenDone);
});
return true;
}
@Override
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.class) {
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
try (EditSession editSession = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world(pos1World)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.build()) {
CuboidRegion region = new CuboidRegion(
BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()),
BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ())
);
editSession.regenerate(region);
editSession.flushQueue();
}
TaskManager.IMP.task(whenDone);
}
});
return true;
}
}

View File

@ -1,131 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweAPI;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
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 final BlockVector3 mutable = new MutableBlockVector3();
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) {
return instance.setBiome(x, 0, z, biomeType);
}
@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,154 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
import com.fastasyncworldedit.core.FaweAPI;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter;
import com.fastasyncworldedit.core.jnbt.CompressedCompoundTag;
import com.fastasyncworldedit.core.jnbt.CompressedSchematicTag;
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;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
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.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.World;
import net.jpountz.lz4.LZ4BlockInputStream;
import org.anarres.parallelgzip.ParallelGZIPOutputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import static org.bukkit.Bukkit.getWorld;
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;
}
return false;
}
@Override
public void getCompoundTag(final String world, final Set<CuboidRegion> regions, final RunnableVal<CompoundTag> whenDone) {
TaskManager.IMP.async(() -> {
Location[] corners = MainUtil.getCorners(world, regions);
Location pos1 = corners[0];
Location pos2 = corners[1];
World adaptedWorld = BukkitAdapter.adapt(getWorld(world));
final CuboidRegion region = new CuboidRegion(
BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()),
BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ())
);
final EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(adaptedWorld)
.checkMemory(false)
.fastMode(true)
.limitUnlimited()
.changeSetNull()
.build();
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
Clipboard holder = new BlockArrayClipboard(region, clipboard);
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
whenDone.run(tag);
});
}
@Override
public boolean save(CompoundTag tag, String path) {
if (tag == null) {
PlotSquared.debug("&cCannot save empty tag");
return false;
}
try {
File tmp = MainUtil.getFile(PlotSquared.get().IMP.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 ParallelGZIPOutputStream(stream)))) {
new FastSchematicWriter(output).write(clipboard);
}
} else {
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(
new ParallelGZIPOutputStream(stream))) {
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
IOUtil.copy(is, stream);
}
}
} else {
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new ParallelGZIPOutputStream(
stream))) {
Map<String, Tag> map = tag.getValue();
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return false;
}
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");
com.github.intellectualsites.plotsquared.plot.util.TaskManager.runTask(whenDone);
return;
}
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
if (weTag instanceof CompressedSchematicTag) {
Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource();
URL url = FaweAPI.upload(clipboard, BuiltInClipboardFormat.SPONGE_SCHEMATIC);
whenDone.run(url);
return;
}
MainUtil.upload(uuid, file, "schem", new RunnableVal<OutputStream>() {
@Override
public void run(OutputStream output) {
try {
try (ParallelGZIPOutputStream gzip = new ParallelGZIPOutputStream(output)) {
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
Map<String, Tag> map = weTag.getValue();
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, whenDone);
}
}

View File

@ -1,58 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
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;
import com.github.intellectualsites.plotsquared.plot.commands.SubCommand;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.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,105 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
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;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.Permissions;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
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 + 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 = WorldEdit.getInstance().newEditSessionBuilder().world(BukkitAdapter.adapt(Bukkit.getWorld(
plot.getArea().worldname)))
.checkMemory(false)
.allowedRegionsEverywhere()
.actor(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,225 +0,0 @@
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
import com.fastasyncworldedit.core.FaweAPI;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.regions.FaweMask;
import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.config.Settings;
import com.github.intellectualsites.plotsquared.plot.database.DBFunc;
import com.github.intellectualsites.plotsquared.plot.flag.Flags;
import com.github.intellectualsites.plotsquared.plot.listener.WEManager;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionIntersection;
import com.sk89q.worldedit.world.World;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class PlotSquaredFeature extends FaweMaskManager {
private static final Logger LOGGER = LogManagerCompat.getLogger();
public PlotSquaredFeature() {
super("PlotSquared");
LOGGER.info("Optimizing PlotSquared");
if (com.fastasyncworldedit.core.configuration.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_V4_HOOK) {
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
try {
setupBlockQueue();
setupSchematicHandler();
setupChunkManager();
} catch (Throwable ignored) {
LOGGER.info("Please update PlotSquared: https://www.spigotmc.org/resources/77506/");
}
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
new FaweTrim();
}
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
new PlotSetBiome();
}
}
// TODO: revisit this later on
/*
try {
if (Settings.Enabled_Components.WORLDS) {
new ReplaceAll();
}
} catch (Throwable e) {
log.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands");
}
*/
}
public static String getName(UUID uuid) {
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 setupChunkManager() throws RuntimeException {
ChunkManager.manager = new FaweChunkManager(ChunkManager.manager);
LOGGER.info(" - ChunkManager: {}", ChunkManager.manager);
}
private void setupSchematicHandler() throws RuntimeException {
SchematicHandler.manager = new FaweSchematicHandler();
LOGGER.info(" - SchematicHandler: {}", SchematicHandler.manager);
}
public boolean isAllowed(Player player, Plot plot, MaskType type) {
if (plot == null) {
return false;
}
UUID uid = player.getUniqueId();
if (Flags.NO_WORLDEDIT.isTrue(plot)) {
player.print(Caption.of(
"fawe.cancel.reason.no.region.reason",
Caption.of("fawe.cancel.reason.no.region.plot.noworldeditflag")
));
return false;
}
if (plot.isOwner(uid) || player.hasPermission("fawe.plotsquared.admin")) {
return true;
}
if (type != MaskType.MEMBER) {
player.print(Caption.of(
"fawe.cancel.reason.no.region.reason",
Caption.of("fawe.cancel.reason.no.region.plot.owner.only")
));
return false;
}
if (plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)) {
return true;
}
if (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) {
if (!player.hasPermission("fawe.plotsquared.member")) {
player.print(Caption.of(
"fawe.cancel.reason.no.region.reason",
Caption.of("fawe.error.no-perm", "fawe.plotsquared.member")
));
return false;
}
if (!plot.getOwners().isEmpty() && plot.getOwners().stream().anyMatch(this::playerOnline)) {
return true;
} else {
player.print(Caption.of(
"fawe.cancel.reason.no.region.reason",
Caption.of("fawe.cancel.reason.no.region.plot.owner.offline")
));
return false;
}
}
player.print(Caption.of(
"fawe.cancel.reason.no.region.reason",
Caption.of("fawe.cancel.reason.no.region.not.added")
));
return false;
}
private boolean playerOnline(UUID uuid) {
if (uuid == null) {
return false;
}
org.bukkit.entity.Player player = Bukkit.getPlayer(uuid);
return player != null && player.isOnline();
}
@Override
public FaweMask getMask(Player player, MaskType type) {
final PlotPlayer pp = PlotPlayer.wrap(player.getUniqueId());
if (pp == null) {
return null;
}
final Set<CuboidRegion> regions;
Plot plot = pp.getCurrentPlot();
if (isAllowed(player, plot, type)) {
regions = plot.getRegions();
} else {
plot = null;
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) {
regions.clear();
}
}
}
if (regions.isEmpty()) {
return null;
}
PlotArea area = pp.getApplicablePlotArea();
int min = area != null ? area.MIN_BUILD_HEIGHT : 0;
int max = area != null ? Math.min(255, area.MAX_BUILD_HEIGHT) : 255;
final HashSet<RegionWrapper> faweRegions = new HashSet<>();
for (CuboidRegion current : regions) {
faweRegions.add(new RegionWrapper(
current.getMinimumX(),
current.getMaximumX(),
min,
max,
current.getMinimumZ(),
current.getMaximumZ()
));
}
final CuboidRegion region = regions.iterator().next();
final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ());
final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ());
final Plot finalPlot = plot;
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot) || regions.isEmpty()) {
return null;
}
Region maskedRegion;
if (regions.size() == 1) {
maskedRegion = new CuboidRegion(pos1, pos2);
} else {
World world = FaweAPI.getWorld(area.worldname);
List<Region> weRegions = regions.stream()
.map(r -> new CuboidRegion(
world,
BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()),
BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ())
))
.collect(Collectors.toList());
maskedRegion = new RegionIntersection(world, weRegions);
}
return new FaweMask(maskedRegion) {
@Override
public boolean isValid(Player player, MaskType type) {
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot)) {
return false;
}
return isAllowed(player, finalPlot, type);
}
};
}
}

View File

@ -34,7 +34,7 @@ public class BukkitItemStack extends BaseItemStack {
@Nullable
@Override
public Object getNativeItem() {
ItemUtil util = Fawe.<FaweBukkit>imp().getItemUtil();
ItemUtil util = Fawe.<FaweBukkit>platform().getItemUtil();
if (util != null && nativeItem == null) {
return nativeItem = util.getNMSItem(stack);
}
@ -58,7 +58,7 @@ public class BukkitItemStack extends BaseItemStack {
public CompoundTag getNbtData() {
if (!loadedNBT) {
loadedNBT = true;
ItemUtil util = Fawe.<FaweBukkit>imp().getItemUtil();
ItemUtil util = Fawe.<FaweBukkit>platform().getItemUtil();
if (util != null) {
super.setNbtData(util.getNBT(stack));
}
@ -68,7 +68,7 @@ public class BukkitItemStack extends BaseItemStack {
@Override
public void setNbtData(@Nullable CompoundTag nbtData) {
ItemUtil util = Fawe.<FaweBukkit>imp().getItemUtil();
ItemUtil util = Fawe.<FaweBukkit>platform().getItemUtil();
if (util != null) {
stack = util.setNBT(stack, nbtData);
nativeItem = null;

View File

@ -12,6 +12,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16);
public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17);
public static final MinecraftVersion CAVES_18 = new MinecraftVersion(1, 18);
private final int major;
private final int minor;
@ -68,7 +69,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
* @param other The other version to compare against.
* @return {@code true} if this version is higher or equal compared to the other version.
*/
public boolean isEqualOrHigher(MinecraftVersion other) {
public boolean isEqualOrHigherThan(MinecraftVersion other) {
return compareTo(other) >= 0;
}
@ -76,7 +77,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
* @param other The other version to compare against.
* @return {@code true} if this version is lower or equal compared to the other version.
*/
public boolean isEqualOrLower(MinecraftVersion other) {
public boolean isEqualOrLowerThan(MinecraftVersion other) {
return compareTo(other) <= 0;
}
@ -84,7 +85,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
* @param other The other version to compare against.
* @return {@code true} if this version is higher than the other version.
*/
public boolean isHigher(MinecraftVersion other) {
public boolean isHigherThan(MinecraftVersion other) {
return compareTo(other) > 0;
}
@ -92,7 +93,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
* @param other The other version to compare against.
* @return {@code true} if this version is lower than to the other version.
*/
public boolean isLower(MinecraftVersion other) {
public boolean isLowerThan(MinecraftVersion other) {
return compareTo(other) < 0;
}
@ -139,6 +140,11 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
return getRelease() == that.getRelease();
}
@Override
public String toString() {
return major + "." + minor + "." + release;
}
/**
* Determines the server version based on the CraftBukkit package path, e.g. {@code org.bukkit.craftbukkit.v1_16_R3},
* where v1_16_R3 is the resolved version.

View File

@ -107,7 +107,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
this.player = player;
//FAWE start
this.permAttachment = plugin.getPermissionAttachmentManager().getOrAddAttachment(player);
if (player != null && Settings.IMP.CLIPBOARD.USE_DISK) {
if (player != null && Settings.settings().CLIPBOARD.USE_DISK) {
BukkitPlayer cached = WorldEditPlugin.getInstance().getCachedPlayer(player);
if (cached == null) {
loadClipboardFromDisk();
@ -169,7 +169,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
player.getInventory().setItemInMainHand(newItem);
HashMap<Integer, ItemStack> overflow = inv.addItem(item);
if (!overflow.isEmpty()) {
TaskManager.IMP.sync(new RunnableVal<>() {
TaskManager.taskManager().sync(new RunnableVal<>() {
@Override
public void run(Object value) {
for (Map.Entry<Integer, ItemStack> entry : overflow.entrySet()) {
@ -243,7 +243,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
}
org.bukkit.World finalWorld = world;
//FAWE end
return TaskManager.IMP.sync(() -> player.teleport(new Location(
return TaskManager.taskManager().sync(() -> player.teleport(new Location(
finalWorld,
pos.getX(),
pos.getY(),

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.bukkit;
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.google.common.collect.Sets;
import com.sk89q.bukkit.util.CommandInfo;
@ -274,9 +275,19 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
RelighterFactory getRelighterFactory() {
if (this.relighterFactory == null) {
this.relighterFactory = this.plugin.getBukkitImplAdapter().getRelighterFactory();
LOGGER.info("Using " + this.relighterFactory.getClass().getCanonicalName() + " as relighter factory.");
LOGGER.info("Using {} as relighter factory.", this.relighterFactory.getClass().getCanonicalName());
}
return this.relighterFactory;
}
@Override
public int versionMinY() {
return new MinecraftVersion().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? -64 : 0;
}
@Override
public int versionMaxY() {
return new MinecraftVersion().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? 319 : 255;
}
//FAWE end
}

View File

@ -301,10 +301,10 @@ public class BukkitWorld extends AbstractWorld {
if (treeTypeMapping.get(type) == null) {
LOGGER.error("No TreeType mapping for TreeGenerator.TreeType." + type);
//FAWE start
LOGGER.info("The above message is displayed because your FAWE version is newer than " + Bukkit.getVersion() +
" and contains features of future minecraft versions which do not exist in "
+ Bukkit.getVersion() + ", hence the tree type " + type + " is not available. This is not an error. " +
"This version will work on your version of Minecraft. This is an informative message only");
LOGGER.info("The above message is displayed because your FAWE version is newer than {}" +
" and contains features of future minecraft versions which do not exist in {} hence the tree type" +
"{} is not available. This is not an error. This version will work on your version of Minecraft." +
"This is an informative message only.", Bukkit.getVersion(), Bukkit.getVersion(), type);
//FAWE end
}
}
@ -317,7 +317,7 @@ public class BukkitWorld extends AbstractWorld {
@Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 pt) {
//FAWE start - allow tree commands to be undone and obey region restrictions
return TaskManager.IMP.sync(() -> WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt,
return TaskManager.taskManager().sync(() -> WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt,
getWorld()
));
//FAWE end
@ -520,7 +520,7 @@ public class BukkitWorld extends AbstractWorld {
public BaseBlock getFullBlock(BlockVector3 position) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position));
return adapter.getFullBlock(BukkitAdapter.adapt(getWorld(), position));
} else {
return getBlock(position).toBaseBlock();
}
@ -555,7 +555,7 @@ public class BukkitWorld extends AbstractWorld {
@Override
public boolean fullySupports3DBiomes() {
// Supports if API does and we're not in the overworld
return HAS_3D_BIOMES && getWorld().getEnvironment() != World.Environment.NORMAL;
return HAS_3D_BIOMES && getWorld().getEnvironment() != World.Environment.NORMAL || PaperLib.isVersion(18);
}
@SuppressWarnings("deprecation")

View File

@ -138,12 +138,12 @@ public class WorldEditPlugin extends JavaPlugin {
platform = new BukkitServerInterface(this, getServer());
worldEdit.getPlatformManager().register(platform);
//FAWE start - Rename config to config-legacy.yml TODO: Chose a better name in the future
createDefaultConfiguration("config-legacy.yml"); // Create the default configuration file for WorldEdit, for us it's 'config-legacy.yml'
//FAWE start - Migrate from config-legacy to worldedit-config
migrateLegacyConfig();
//FAWE end
//FAWE start - Modify WorldEdit config name
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "config-legacy.yml"), true), this);
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this);
//FAWE end
//FAWE start - Setup permission attachments
@ -220,8 +220,6 @@ public class WorldEditPlugin extends JavaPlugin {
// Enable metrics
new Metrics(this, BSTATS_ID);
// Check whether the server runs on 11 or greater
ServerLib.checkJavaLTS();
// Check if we are in a safe environment
ServerLib.checkUnsafeForks();
// Check if a new build is available
@ -369,8 +367,8 @@ public class WorldEditPlugin extends JavaPlugin {
} else {
//FAWE start - Identify as FAWE
LOGGER.info("FastAsyncWorldEdit could not find a Bukkit adapter for this MC version, "
+ "but it seems that you have another implementation of FastAsyncWorldEdit installed (" + platform.getPlatformName() + ") "
+ "that handles the world editing.");
+ "but it seems that you have another implementation of FastAsyncWorldEdit installed ({}) "
+ "that handles the world editing.", platform.getPlatformName());
//FAWE end
}
this.adapter.invalidate();
@ -382,7 +380,7 @@ public class WorldEditPlugin extends JavaPlugin {
*/
@Override
public void onDisable() {
Fawe.get().onDisable();
Fawe.instance().onDisable();
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
if (platform != null) {
@ -424,6 +422,19 @@ public class WorldEditPlugin extends JavaPlugin {
}
}
private void migrateLegacyConfig() {
File legacy = new File(getDataFolder(), "config-legacy.yml");
if (legacy.exists()) {
try {
legacy.renameTo(new File(getDataFolder(), "worldedit-config.yml"));
LOGGER.info("Migrated config-legacy.yml to worldedit-config.yml");
} catch (Exception e) {
LOGGER.error("Unable to rename legacy config file", e);
}
}
createDefaultConfiguration("worldedit-config.yml");
}
private void copyDefaultConfig(InputStream input, File actual, String name) {
try (FileOutputStream output = new FileOutputStream(actual)) {
byte[] buf = new byte[8192];

View File

@ -106,7 +106,15 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
* @param location the location
* @return the block
*/
BaseBlock getBlock(Location location);
BlockState getBlock(Location location);
/**
* Get the block at the given location.
*
* @param location the location
* @return the block
*/
BaseBlock getFullBlock(Location location);
/**
* Create a {@link WorldNativeAccess} for the given world reference.
@ -306,7 +314,7 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
@Nullable
default World createWorld(WorldCreator creator) {
return ((FaweBukkit) Fawe.imp()).createWorldUnloaded(creator::createWorld);
return ((FaweBukkit) Fawe.platform()).createWorldUnloaded(creator::createWorld);
}
/**

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.bukkit.adapter;
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.util.io.Closer;
import org.apache.logging.log4j.Logger;
@ -39,6 +40,8 @@ public class BukkitImplLoader {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final List<String> adapterCandidates = new ArrayList<>();
private final String minorMCVersion = String.valueOf(new MinecraftVersion().getMinor());
private int zeroth = 0;
private String customCandidate;
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl.fawe";
@ -73,6 +76,7 @@ public class BukkitImplLoader {
String className = System.getProperty("worldedit.bukkit.adapter");
if (className != null) {
customCandidate = className;
zeroth = 1;
adapterCandidates.add(className);
LOGGER.info("-Dworldedit.bukkit.adapter used to add " + className + " to the list of available Bukkit adapters");
}
@ -101,7 +105,11 @@ public class BukkitImplLoader {
int beginIndex = 0;
int endIndex = className.length() - CLASS_SUFFIX.length();
className = className.substring(beginIndex, endIndex);
adapterCandidates.add(className);
if (className.contains(minorMCVersion)) {
adapterCandidates.add(zeroth, className);
} else {
adapterCandidates.add(className);
}
}
} finally {
closer.close();
@ -142,7 +150,11 @@ public class BukkitImplLoader {
int beginIndex = 0;
int endIndex = resource.length() - CLASS_SUFFIX.length();
String className = resource.substring(beginIndex, endIndex);
adapterCandidates.add(className);
if (className.contains(minorMCVersion)) {
adapterCandidates.add(zeroth, className);
} else {
adapterCandidates.add(className);
}
}
}

View File

@ -10,39 +10,39 @@
# in categories, like "max-blocks-changed", are placed in the "limits"
# category.
# - If you want to check the format of this file before putting it
# into WorldEdit, paste it into http://yaml-online-parser.appspot.com/
# into WorldEdit, paste it into https://yaml-online-parser.appspot.com/
# and see if it gives you "ERROR:".
# - Lines starting with # are comments, so they are ignored.
# - If you want to allow blocks, make sure to change "disallowed-blocks" to []
#
limits :
max-blocks-changed :
limits:
max-blocks-changed:
# Ignored, use FAWE config limits
default : -1
maximum : -1
max-polygonal-points :
default : -1
maximum : 20
max-radius : -1
max-super-pickaxe-size : 5
max-brush-radius : 100
butcher-radius :
default : -1
maximum : -1
disallowed-blocks :
default: -1
maximum: -1
max-polygonal-points:
default: -1
maximum: 20
max-radius: -1
max-super-pickaxe-size: 5
max-brush-radius: 100
butcher-radius:
default: -1
maximum: -1
disallowed-blocks:
- "minecraft:wheat"
- "minecraft:fire"
- "minecraft:redstone_wire"
use-inventory :
enable : false
allow-override : true
creative-mode-overrides : false
use-inventory:
enable: false
allow-override: true
creative-mode-overrides: false
logging :
log-commands : false
file : worldedit.log
logging:
log-commands: false
file: worldedit.log
# The format of custom log message. This is java general format string (java.util.Formatter). Arguments are:
# 1$ : date - a Date object representing event time of the log record.
# 2$ : source - a string representing the caller, if available; otherwise, the logger's name.
@ -53,44 +53,44 @@ logging :
# For details see:
# https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html
# https://docs.oracle.com/javase/8/docs/api/java/util/logging/SimpleFormatter.html#format-java.util.logging.LogRecord-
format : "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n"
format: "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n"
super-pickaxe :
drop-items : true
many-drop-items : false
super-pickaxe:
drop-items: true
many-drop-items: false
snapshots :
directory :
snapshots:
directory:
navigation-wand :
item : minecraft:compass
max-distance : 100
navigation-wand:
item: minecraft:compass
max-distance: 100
scripting :
timeout : 3000
dir : craftscripts
scripting:
timeout: 3000
dir: craftscripts
saving :
dir : schematics
saving:
dir: schematics
files :
allow-symbolic-links : false
files:
allow-symbolic-links: false
history :
size : 15
expiration : 10
history:
size: 15
expiration: 10
calculation :
timeout : 100
calculation:
timeout: 100
debugging :
trace-unflushed-sessions : false
debugging:
trace-unflushed-sessions: false
wand-item : minecraft:wooden_axe
shell-save-type :
no-double-slash : false
no-op-permissions : false
debug : false
show-help-on-first-use : true
server-side-cui : true
command-block-support : false
wand-item: minecraft:wooden_axe
shell-save-type:
no-double-slash: false
no-op-permissions: false
debug: false
show-help-on-first-use: true
server-side-cui: true
command-block-support: false

View File

@ -20,14 +20,14 @@ public class MinecraftVersionTest {
@Test
public void testEqualOrHigher() {
assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 3)));
assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 2)));
assertFalse(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16, 4)));
assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 3)));
assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 2)));
assertFalse(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16, 4)));
}
@Test
public void testEqualOrHigherWithoutRelease() {
assertTrue(latestVersion.isEqualOrHigher(new MinecraftVersion(1, 16)));
assertTrue(latestVersion.isEqualOrHigherThan(new MinecraftVersion(1, 16)));
}
@Test
@ -39,15 +39,15 @@ public class MinecraftVersionTest {
@Test
public void testEqualOrLower() {
assertTrue(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 3)));
assertTrue(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 4)));
assertFalse(latestVersion.isEqualOrLower(new MinecraftVersion(1, 16, 2)));
assertTrue(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 3)));
assertTrue(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 4)));
assertFalse(latestVersion.isEqualOrLowerThan(new MinecraftVersion(1, 16, 2)));
}
@Test
public void testForChunkStretched() {
assertTrue(latestVersion.isEqualOrHigher(MinecraftVersion.NETHER));
assertFalse(latestVersion.isLower(new MinecraftVersion(1, 14, 2)));
assertTrue(latestVersion.isEqualOrHigherThan(MinecraftVersion.NETHER));
assertFalse(latestVersion.isLowerThan(new MinecraftVersion(1, 14, 2)));
}
}

View File

@ -118,6 +118,11 @@ public class StubServer implements Server {
return 0;
}
@Override
public int getSimulationDistance() {
return 12;
}
@Override
public @NotNull
String getIp() {
@ -150,6 +155,26 @@ public class StubServer implements Server {
return false;
}
@Override
public @NotNull String getResourcePack() {
return null;
}
@Override
public @NotNull String getResourcePackHash() {
return null;
}
@Override
public @NotNull String getResourcePackPrompt() {
return null;
}
@Override
public boolean isResourcePackRequired() {
return false;
}
@Override
public boolean hasWhitelist() {
return false;
@ -465,6 +490,11 @@ public class StubServer implements Server {
}
@Override
public boolean getHideOnlinePlayers() {
return false;
}
@Override
public boolean getOnlineMode() {
return false;

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
@ -169,6 +170,16 @@ class CLIPlatform extends AbstractPlatform {
return (_a, _b, _c) -> NullRelighter.INSTANCE;
}
@Override
public int versionMinY() {
return dataVersion >= Constants.DATA_VERSION_MC_1_18 ? -64 : 0;
}
@Override
public int versionMaxY() {
return dataVersion >= Constants.DATA_VERSION_MC_1_18 ? 319 : 255;
}
public void addWorld(World world) {
worlds.add(world);
}

View File

@ -190,7 +190,7 @@ public class CLIWorldEdit {
this.commandSender = new CLICommandSender(this, LOGGER);
this.platform = new CLIPlatform(this);
//FAWE start - identify as Fawe
LOGGER.info("FastAsyncWorldEdit CLI (version " + getInternalVersion() + ") is loaded");
LOGGER.info("FastAsyncWorldEdit CLI (version {}) is loaded", getInternalVersion());
//FAWE end
}

View File

@ -12,7 +12,7 @@ applyPlatformAndCoreConfiguration()
dependencies {
constraints {
implementation("org.yaml:snakeyaml") {
version { strictly("1.28") }
version { strictly("1.30") }
because("Bukkit provides SnakeYaml")
}
}
@ -37,7 +37,6 @@ dependencies {
// Plugins
compileOnly(libs.redprotect) { isTransitive = false }
compileOnly(libs.plotsquaredV4) { isTransitive = false }
compileOnly(libs.plotsquaredV6Core) { isTransitive = false }
// ensure this is on the classpath for the AP

View File

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.5.0-RC"
kotlin("jvm") version "1.5.30"
application
}

View File

@ -101,17 +101,17 @@ public class Fawe {
this.setupConfigs();
TaskManager.IMP = this.implementation.getTaskManager();
TaskManager.IMP.async(() -> {
TaskManager.taskManager().async(() -> {
MainUtil.deleteOlder(
MainUtil.getFile(this.implementation
.getDirectory(), Settings.IMP.PATHS.HISTORY),
TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS),
.getDirectory(), Settings.settings().PATHS.HISTORY),
TimeUnit.DAYS.toMillis(Settings.settings().HISTORY.DELETE_AFTER_DAYS),
false
);
MainUtil.deleteOlder(
MainUtil.getFile(this.implementation
.getDirectory(), Settings.IMP.PATHS.CLIPBOARD),
TimeUnit.DAYS.toMillis(Settings.IMP.CLIPBOARD.DELETE_AFTER_DAYS),
.getDirectory(), Settings.settings().PATHS.CLIPBOARD),
TimeUnit.DAYS.toMillis(Settings.settings().CLIPBOARD.DELETE_AFTER_DAYS),
false
);
});
@ -123,28 +123,49 @@ public class Fawe {
this.timer = new FaweTimer();
// Delayed worldedit setup
TaskManager.IMP.later(() -> {
TaskManager.taskManager().later(() -> {
try {
WEManager.IMP.addManagers(Fawe.this.implementation.getMaskManagers());
WEManager.weManager().addManagers(Fawe.this.implementation.getMaskManagers());
} catch (Throwable ignored) {
}
}, 0);
TaskManager.IMP.repeat(timer, 1);
TaskManager.taskManager().repeat(timer, 1);
}
/**
* Get the implementation specific class.
* @deprecated use {@link #platform()}
*/
@SuppressWarnings("unchecked")
@Deprecated(forRemoval = true, since = "2.0.0")
public static <T extends IFawe> T imp() {
return instance != null ? (T) instance.implementation : null;
}
/**
* Get the implementation specific class.
* @since 2.0.0
*/
@SuppressWarnings("unchecked")
public static <T extends IFawe> T platform() {
return instance != null ? (T) instance.implementation : null;
}
/**
* Get the implementation independent class.
* @deprecated use {@link #instance()}
*/
@Deprecated(forRemoval = true, since = "2.0.0")
public static Fawe get() {
return instance;
}
/**
* Get the implementation independent class.
*/
public static Fawe get() {
public static Fawe instance() {
return instance;
}
@ -225,8 +246,8 @@ public class Fawe {
}
public void onDisable() {
if (imp().getPreloader(false) != null) {
imp().getPreloader(false).cancel();
if (platform().getPreloader(false) != null) {
platform().getPreloader(false).cancel();
}
}
@ -296,7 +317,7 @@ public class Fawe {
MainUtil.copyFile(MainUtil.getJarFile(), "lang/strings.json", null);
// Setting up config.yml
File file = new File(this.implementation.getDirectory(), "config.yml");
Settings.IMP.PLATFORM = implementation.getPlatform().replace("\"", "");
Settings.settings().PLATFORM = implementation.getPlatform().replace("\"", "");
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String versionString = br.readLine();
@ -304,17 +325,17 @@ public class Fawe {
String dateString = br.readLine();
br.close();
this.version = FaweVersion.tryParse(versionString, commitString, dateString);
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toString();
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-1.17/" + version.build;
Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash);
Settings.settings().DATE = new Date(100 + version.year, version.month, version.day).toString();
Settings.settings().BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
Settings.settings().COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash);
} catch (Throwable ignored) {
}
try {
Settings.IMP.reload(file);
Settings.settings().reload(file);
} catch (Throwable e) {
LOGGER.error("Failed to load config.", e);
}
Settings.IMP.QUEUE.TARGET_SIZE = Math.max(Settings.IMP.QUEUE.TARGET_SIZE, Settings.IMP.QUEUE.PARALLEL_THREADS);
Settings.settings().QUEUE.TARGET_SIZE = Math.max(Settings.settings().QUEUE.TARGET_SIZE, Settings.settings().QUEUE.PARALLEL_THREADS);
try {
byte[] in = new byte[0];
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
@ -332,14 +353,14 @@ public class Fawe {
assert (Zstd.decompress(ob, compressed) == 0);
LOGGER.info("ZSTD Compression Binding loaded successfully");
} catch (Throwable e) {
if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.IMP.HISTORY.COMPRESSION_LEVEL > 6) {
Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL);
Settings.IMP.HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.HISTORY.COMPRESSION_LEVEL);
if (Settings.settings().CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.settings().HISTORY.COMPRESSION_LEVEL > 6) {
Settings.settings().CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.settings().CLIPBOARD.COMPRESSION_LEVEL);
Settings.settings().HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.settings().HISTORY.COMPRESSION_LEVEL);
LOGGER.error("ZSTD Compression Binding Not Found.\n"
+ "FAWE will still work but compression won't work as well.", e);
}
}
Settings.IMP.save(file);
Settings.settings().save(file);
}
public WorldEdit getWorldEdit() {
@ -347,7 +368,7 @@ public class Fawe {
}
private void setupMemoryListener() {
if (Settings.IMP.MAX_MEMORY_PERCENT < 1 || Settings.IMP.MAX_MEMORY_PERCENT > 99) {
if (Settings.settings().MAX_MEMORY_PERCENT < 1 || Settings.settings().MAX_MEMORY_PERCENT > 99) {
return;
}
try {
@ -371,7 +392,7 @@ public class Fawe {
if (max < 0) {
continue;
}
final long alert = (max * Settings.IMP.MAX_MEMORY_PERCENT) / 100;
final long alert = (max * Settings.settings().MAX_MEMORY_PERCENT) / 100;
mp.setUsageThreshold(alert);
}
}

View File

@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.fastasyncworldedit.core.util.EditSessionBuilder;
import com.fastasyncworldedit.core.util.MainUtil;
import com.fastasyncworldedit.core.util.MemUtil;
import com.fastasyncworldedit.core.util.TaskManager;
@ -60,24 +59,13 @@ public class FaweAPI {
private static final Logger LOGGER = LogManagerCompat.getLogger();
/**
* Offers a lot of options for building an EditSession.
*
* @return A new EditSessionBuilder
* @deprecated See {@link WorldEdit#newEditSessionBuilder()}
*/
@Deprecated(forRemoval = true)
public static EditSessionBuilder getEditSessionBuilder(World world) {
return new EditSessionBuilder(world);
}
/**
* The TaskManager has some useful methods for doing things asynchronously.
*
* @return TaskManager
*/
public static TaskManager getTaskManager() {
return TaskManager.IMP;
return TaskManager.taskManager();
}
/**
@ -93,7 +81,7 @@ public class FaweAPI {
* @return the queue extent
*/
public static IQueueExtent<IQueueChunk> createQueue(World world, boolean autoQueue) {
IQueueExtent<IQueueChunk> queue = Fawe.get().getQueueHandler().getQueue(world);
IQueueExtent<IQueueChunk> queue = Fawe.instance().getQueueHandler().getQueue(world);
if (!autoQueue) {
queue.disableQueue();
}
@ -139,7 +127,7 @@ public class FaweAPI {
* @return Set of FaweMaskManager
*/
public static Set<FaweMaskManager> getMaskManagers() {
return new HashSet<>(WEManager.IMP.getManagers());
return new HashSet<>(WEManager.weManager().getManagers());
}
/**
@ -155,7 +143,7 @@ public class FaweAPI {
* Get a player's allowed WorldEdit region(s).
*/
public static Region[] getRegions(Player player) {
return WEManager.IMP.getMask(player);
return WEManager.weManager().getMask(player);
}
/**
@ -167,7 +155,7 @@ public class FaweAPI {
* @return array of allowed regions if whitelist, else of disallowed regions.
*/
public static Region[] getRegions(Player player, FaweMaskManager.MaskType type, boolean isWhiteList) {
return WEManager.IMP.getMask(player, type, isWhiteList);
return WEManager.weManager().getMask(player, type, isWhiteList);
}
/**
@ -182,13 +170,13 @@ public class FaweAPI {
*/
public static void cancelEdit(AbstractDelegateExtent extent, Component reason) {
try {
WEManager.IMP.cancelEdit(extent, new FaweException(reason));
WEManager.weManager().cancelEdit(extent, new FaweException(reason));
} catch (WorldEditException ignored) {
}
}
public static void addMaskManager(FaweMaskManager maskMan) {
WEManager.IMP.addManager(maskMan);
WEManager.weManager().addManager(maskMan);
}
/**
@ -198,7 +186,7 @@ public class FaweAPI {
if (!file.exists() || file.isDirectory()) {
throw new IllegalArgumentException("Not a file!");
}
if (Settings.IMP.HISTORY.USE_DISK) {
if (Settings.settings().HISTORY.USE_DISK) {
throw new IllegalArgumentException("History on disk not enabled!");
}
if (!file.getName().toLowerCase(Locale.ROOT).endsWith(".bd")) {
@ -236,11 +224,10 @@ public class FaweAPI {
*/
public static List<DiskStorageHistory> getBDFiles(Location origin, UUID user, int radius, long timediff, boolean shallow) {
Extent extent = origin.getExtent();
if (!(extent instanceof World)) {
if (!(extent instanceof World world)) {
throw new IllegalArgumentException("Origin is not a valid world");
}
World world = (World) extent;
File history = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName());
File history = MainUtil.getFile(Fawe.platform().getDirectory(), Settings.settings().PATHS.HISTORY + File.separator + world.getName());
if (!history.exists()) {
return new ArrayList<>();
}
@ -364,12 +351,12 @@ public class FaweAPI {
World unwrapped = WorldWrapper.unwrap(world);
if (unwrapped instanceof IQueueExtent) {
queue = (IQueueExtent) unwrapped;
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1) {
} else if (Settings.settings().QUEUE.PARALLEL_THREADS > 1) {
ParallelQueueExtent parallel =
new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, true);
new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, true);
queue = parallel.getExtent();
} else {
queue = Fawe.get().getQueueHandler().getQueue(world);
queue = Fawe.instance().getQueueHandler().getQueue(world);
}
}
@ -384,7 +371,7 @@ public class FaweAPI {
}
}
if (mode != RelightMode.NONE) {
if (Settings.IMP.LIGHTING.REMOVE_FIRST) {
if (Settings.settings().LIGHTING.REMOVE_FIRST) {
relighter.removeAndRelight(true);
} else {
relighter.fixSkyLighting();

View File

@ -59,7 +59,15 @@ import java.util.function.Supplier;
import static com.google.common.base.Preconditions.checkNotNull;
public enum FaweCache implements Trimable {
IMP; // singleton
/**
* @deprecated Use {@link #INSTANCE} to get an instance.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
IMP,
/**
* @since 2.0.0
*/
INSTANCE;
private static final Logger LOGGER = LogManagerCompat.getLogger();
@ -301,7 +309,7 @@ public enum FaweCache implements Trimable {
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
@ -387,7 +395,7 @@ public enum FaweCache implements Trimable {
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
@ -568,7 +576,7 @@ public enum FaweCache implements Trimable {
Thread stuff
*/
public ThreadPoolExecutor newBlockingExecutor() {
int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS;
int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads, true);
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS, queue,
@ -609,7 +617,7 @@ public enum FaweCache implements Trimable {
lastException = hash;
LOGGER.catching(throwable);
count = 0;
} else if (count < Settings.IMP.QUEUE.PARALLEL_THREADS) {
} else if (count < Settings.settings().QUEUE.PARALLEL_THREADS) {
LOGGER.warn(throwable.getMessage());
count++;
}

View File

@ -1,5 +1,9 @@
package com.fastasyncworldedit.core;
import com.fastasyncworldedit.core.util.StringMan;
import java.util.Locale;
/**
* An internal FAWE class not meant for public use.
**/
@ -10,28 +14,35 @@ public class FaweVersion {
public final int day;
public final int hash;
public final int build;
public final int[] semver;
public final boolean snapshot;
public FaweVersion(int year, int month, int day, int hash, int build) {
public FaweVersion(int year, int month, int day, int[] semver, boolean snapshot, int hash, int build) {
this.year = year;
this.month = month;
this.day = day;
this.hash = hash;
this.build = build;
this.semver = semver;
this.snapshot = snapshot;
}
public FaweVersion(String version, String commit, String date) {
String[] split = version.substring(version.indexOf('=') + 1).split("-");
int build = 0;
try {
build = Integer.parseInt(split[1]);
} catch (NumberFormatException ignored) {
String[] split1 = split[0].split("\\.");
int[] ver = new int[3];
for (int i = 0; i < 3; i++) {
ver[i] = Integer.parseInt(split1[i]);
}
this.build = build;
this.semver = ver;
this.snapshot = split.length > 1 && split[1].toLowerCase(Locale.ROOT).contains("snapshot");
int buildIndex = this.snapshot ? 2 : 1;
this.build = split.length == buildIndex + 1 ? Integer.parseInt(split[buildIndex]) : 0;
this.hash = Integer.parseInt(commit.substring(commit.indexOf('=') + 1), 16);
String[] split1 = date.substring(date.indexOf('=') + 1).split("\\.");
this.year = Integer.parseInt(split1[0]);
this.month = Integer.parseInt(split1[1]);
this.day = Integer.parseInt(split1[2]);
String[] split2 = date.substring(date.indexOf('=') + 1).split("\\.");
this.year = Integer.parseInt(split2[0]);
this.month = Integer.parseInt(split2[1]);
this.day = Integer.parseInt(split2[2]);
}
public static FaweVersion tryParse(String version, String commit, String date) {
@ -39,28 +50,42 @@ public class FaweVersion {
return new FaweVersion(version, commit, date);
} catch (Exception exception) {
exception.printStackTrace();
return new FaweVersion(0, 0, 0, 0, 0);
return new FaweVersion(0, 0, 0, null, true, 0, 0);
}
}
@Override
public String toString() {
if (hash == 0 && build == 0) {
return getSimpleVersionName() + "-NoVer-SNAPSHOT";
if (semver == null) {
return "FastAsyncWorldEdit-NoVer-SNAPSHOT";
} else {
return getSimpleVersionName() + "-" + build;
String snapshot = this.snapshot ? "-SNAPSHOT" : "";
String build = this.build > 0 ? "-" + this.build : "";
return "FastAsyncWorldEdit-" + StringMan.join(semver, ".") + snapshot + build;
}
}
/**
* @return The qualified version name
* Returns if another FaweVersion is newer than this one
*/
public String getSimpleVersionName() {
return "FastAsyncWorldEdit-1.17";
}
public boolean isNewer(FaweVersion other) {
return other.build < this.build;
if (other.semver == null) {
return other.build > this.build;
}
if (this.semver == null) {
return true;
}
if (other.semver[0] != this.semver[0]) {
return other.semver[0] > this.semver[0];
} else if (other.semver[1] != this.semver[1]) {
return other.semver[1] > this.semver[1];
} else if (other.semver[2] != this.semver[2]) {
return other.semver[2] > this.semver[2];
}
if (other.snapshot == this.snapshot) {
return other.build > this.build;
}
return !other.snapshot;
}
}

View File

@ -531,7 +531,7 @@ public class AnvilCommands {
// });
// if (useData) {
// for (long[] c : map) {
// BaseBlock block = FaweCache.IMP.CACHE_BLOCK[(int) c[0]];
// BaseBlock block = FaweCache.INSTANCE.CACHE_BLOCK[(int) c[0]];
// String name = BlockType.fromID(block.getId()).getName();
// String str = String.format("%-7s (%.3f%%) %s #%d:%d",
// String.valueOf(c[1]),

View File

@ -147,7 +147,7 @@
// CFISettings settings = getSettings(player).remove();
// generator.setPacketViewer(player);
// settings.setGenerator(generator).bind();
// generator.setImageViewer(Fawe.imp().getImageViewer(player));
// generator.setImageViewer(Fawe.platform().getImageViewer(player));
// generator.update();
// mainMenu(player);
// }
@ -226,7 +226,7 @@
// World world = FaweAPI.getWorld(folder.getName());
// if (world != null) {
// if (player.getWorld() != world) {
// TaskManager.IMP.sync(new RunnableVal<Object>() {
// TaskManager.taskManager().sync(new RunnableVal<Object>() {
// @Override
// public void run(Object value) {
// Location spawn = new Location(world, world.getSpawnPosition().toVector3());
@ -425,7 +425,7 @@
// switch (argOpt.toLowerCase(Locale.ROOT)) {
// case "true":
// case "*": {
// generator.setTextureUtil(Fawe.get().getTextureUtil());
// generator.setTextureUtil(Fawe.instance().getTextureUtil());
// return;
// }
// case "#clipboard": {
@ -453,7 +453,7 @@
// parserContext.setExtent(extent);
// Request.request().setExtent(extent);
// Mask mask = worldEdit.getMaskFactory().parseFromInput(argOpt, parserContext);
// TextureUtil tu = Fawe.get().getTextureUtil();
// TextureUtil tu = Fawe.instance().getTextureUtil();
// for (int typeId : tu.getValidBlockIds()) {
// BlockType type = BlockTypes.get(typeId);
// extent.init(0, 0, 0, type.getDefaultState().toBaseBlock());
@ -464,7 +464,7 @@
// break;
// }
// }
// generator.setTextureUtil(new FilteredTextureUtil(Fawe.get().getTextureUtil(), blocks));
// generator.setTextureUtil(new FilteredTextureUtil(Fawe.instance().getTextureUtil(), blocks));
// coloring(player);
// }
//
@ -493,9 +493,9 @@
// public void complexity(Player player, int min, int max) throws FileNotFoundException {
// HeightMapMCAGenerator gen = assertSettings(player).getGenerator();
// if (min == 0 && max == 100) {
// gen.setTextureUtil(Fawe.get().getTextureUtil());
// gen.setTextureUtil(Fawe.instance().getTextureUtil());
// } else {
// gen.setTextureUtil(new CleanTextureUtil(Fawe.get().getTextureUtil(), min, max));
// gen.setTextureUtil(new CleanTextureUtil(Fawe.instance().getTextureUtil(), min, max));
// }
// coloring(player);
// }
@ -1201,7 +1201,7 @@
// whiteOnly = true;
// maskArg = null;
// imageMaskArg = null;
// generator.setTextureUtil(Fawe.get().getTextureUtil());
// generator.setTextureUtil(Fawe.instance().getTextureUtil());
// }
//
// public void resetComponent() {

View File

@ -95,7 +95,7 @@ public class ListFilters {
}
String firstArg = finalArg.substring(0, finalArg.length() - File.separator.length());
if (firstArg.length() > 3 && firstArg.length() <= 16) {
UUID fromName = Fawe.imp().getUUID(finalArg);
UUID fromName = Fawe.platform().getUUID(finalArg);
if (fromName != null) {
newRoot = new File(root, finalArg);
if (newRoot.exists()) {

View File

@ -45,7 +45,7 @@
// PlotPlayer player = PlotPlayer.get(actor.getName());
//
// actor.print("Claiming world");
// Plot plot = TaskManager.IMP.sync(new RunnableVal<Plot>() {
// Plot plot = TaskManager.taskManager().sync(new RunnableVal<Plot>() {
// @Override
// public void run(Plot o) {
// int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount()
@ -73,7 +73,7 @@
// File folder = CFICommands.getFolder(plot.getWorldName());
// Boolean result = createTask.apply(folder);
// if (result == Boolean.TRUE) {
// TaskManager.IMP.sync(() -> plot.teleportPlayer(player));
// TaskManager.taskManager().sync(() -> plot.teleportPlayer(player));
// }
// return;
// }

View File

@ -90,7 +90,7 @@ public class BrushSettings {
// }
// if (settings.containsKey(SettingType.TRANSFORM.name())) {
// String transformArgs = (String) settings.get(SettingType.TRANSFORM.name());
// ResettableExtent extent = Fawe.get().getTransformParser().parseFromInput(transformArgs, parserContext);
// ResettableExtent extent = Fawe.instance().getTransformParser().parseFromInput(transformArgs, parserContext);
// bs.setTransform(extent);
// bs.constructor.put(SettingType.TRANSFORM, transformArgs);
// }

View File

@ -68,7 +68,7 @@ public class InspectBrush extends BrushTool {
player.print(Caption.of("fawe.error.no-perm", "worldedit.tool.inspect"));
return false;
}
if (!Settings.IMP.HISTORY.USE_DATABASE) {
if (!Settings.settings().HISTORY.USE_DATABASE) {
player.print(Caption.of(
"fawe.error.setting.disable",
"history.use-database (Import with /history import )"
@ -81,7 +81,7 @@ public class InspectBrush extends BrushTool {
final int y = target.getBlockY();
final int z = target.getBlockZ();
World world = player.getWorld();
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
RollbackDatabase db = DBHandler.dbHandler().getDatabase(world);
int count = 0;
for (Supplier<RollbackOptimizedHistory> supplier : db.getEdits(target, false)) {
count++;
@ -95,7 +95,7 @@ public class InspectBrush extends BrushTool {
int from = change.from;
int to = change.to;
UUID uuid = edit.getUUID();
String name = Fawe.imp().getName(uuid);
String name = Fawe.platform().getName(uuid);
int index = edit.getIndex();
long age = System.currentTimeMillis() - edit.getBDFile().lastModified();
String ageFormatted = MainUtil.secToTime(age / 1000);

View File

@ -34,7 +34,7 @@ public class Config {
/**
* Get the value for a node. Probably throws some error if you try to get a non-existent key.
*/
private <T> T get(String key, Class root) {
private <T> T get(String key, Class<?> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -57,7 +57,7 @@ public class Config {
* @param key config node
* @param value value
*/
private void set(String key, Object value, Class root) {
private void set(String key, Object value, Class<?> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -201,7 +201,7 @@ public class Config {
/**
* Get the static fields in a section.
*/
private Map<String, Object> getFields(Class clazz) {
private Map<String, Object> getFields(Class<?> clazz) {
HashMap<String, Object> map = new HashMap<>();
for (Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) {
@ -223,12 +223,11 @@ public class Config {
}
StringBuilder m = new StringBuilder();
for (Object obj : listValue) {
m.append(System.lineSeparator() + spacing + "- " + toYamlString(obj, spacing));
m.append(System.lineSeparator()).append(spacing).append("- ").append(toYamlString(obj, spacing));
}
return m.toString();
}
if (value instanceof String) {
String stringValue = (String) value;
if (value instanceof String stringValue) {
if (stringValue.isEmpty()) {
return "''";
}
@ -237,11 +236,11 @@ public class Config {
return value != null ? value.toString() : "null";
}
private void save(PrintWriter writer, Class clazz, final Object instance, int indent) {
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) {
try {
String CTRF = System.lineSeparator();
String spacing = StringMan.repeat(" ", indent);
HashMap<Class, Object> instances = new HashMap<>();
HashMap<Class<?>, Object> instances = new HashMap<>();
for (Field field : clazz.getFields()) {
if (field.getAnnotation(Ignore.class) != null) {
continue;
@ -272,7 +271,7 @@ public class Config {
configBlock = new ConfigBlock();
field.set(instance, configBlock);
for (String blockName : blockNames.value()) {
configBlock.put(blockName, current.newInstance());
configBlock.put(blockName, current.getDeclaredConstructor().newInstance());
}
}
// Save each instance
@ -299,11 +298,10 @@ public class Config {
}
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
if (value == null) {
field.set(instance, value = current.newInstance());
field.set(instance, value = current.getDeclaredConstructor().newInstance());
instances.put(current, value);
}
save(writer, current, value, indent + 2);
continue;
} else {
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(
field.get(instance),
@ -321,7 +319,7 @@ public class Config {
*
* @param split the node (split by period)
*/
private Field getField(String[] split, Class root) {
private Field getField(String[] split, Class<?> root) {
Object instance = getInstance(split, root);
if (instance == null) {
return null;
@ -352,74 +350,64 @@ public class Config {
}
}
private Object getInstance(Object instance, Class clazz) throws IllegalAccessException, InstantiationException {
try {
Field instanceField = clazz.getDeclaredField(clazz.getSimpleName());
} catch (Throwable ignored) {
}
return clazz.newInstance();
}
/**
* Get the instance for a specific config node.
*
* @param split the node (split by period)
* @return The instance or null
*/
private Object getInstance(String[] split, Class root) {
private Object getInstance(String[] split, Class<?> root) {
try {
Class<?> clazz = root == null ? MethodHandles.lookup().lookupClass() : root;
Object instance = this;
while (split.length > 0) {
switch (split.length) {
case 1:
return instance;
default:
Class found = null;
Class<?>[] classes = clazz.getDeclaredClasses();
for (Class current : classes) {
if (StringMan.isEqual(current.getSimpleName(), toFieldName(split[0]))) {
found = current;
break;
}
}
try {
Field instanceField = clazz.getDeclaredField(toFieldName(split[0]));
setAccessible(instanceField);
if (instanceField.getType() != ConfigBlock.class) {
Object value = instanceField.get(instance);
if (value == null) {
value = found.newInstance();
instanceField.set(instance, value);
}
clazz = found;
instance = value;
split = Arrays.copyOfRange(split, 1, split.length);
continue;
}
ConfigBlock value = (ConfigBlock) instanceField.get(instance);
if (value == null) {
value = new ConfigBlock();
instanceField.set(instance, value);
}
instance = value.get(split[1]);
if (instance == null) {
instance = found.newInstance();
value.put(split[1], instance);
}
clazz = found;
split = Arrays.copyOfRange(split, 2, split.length);
continue;
} catch (NoSuchFieldException ignored) {
}
if (found != null) {
split = Arrays.copyOfRange(split, 1, split.length);
clazz = found;
instance = clazz.newInstance();
continue;
}
return null;
if (split.length == 1) {
return instance;
}
Class<?> found = null;
Class<?>[] classes = clazz.getDeclaredClasses();
for (Class<?> current : classes) {
if (StringMan.isEqual(current.getSimpleName(), toFieldName(split[0]))) {
found = current;
break;
}
}
try {
Field instanceField = clazz.getDeclaredField(toFieldName(split[0]));
setAccessible(instanceField);
if (instanceField.getType() != ConfigBlock.class) {
Object value = instanceField.get(instance);
if (value == null) {
value = found.getDeclaredConstructor().newInstance();
instanceField.set(instance, value);
}
clazz = found;
instance = value;
split = Arrays.copyOfRange(split, 1, split.length);
continue;
}
ConfigBlock value = (ConfigBlock) instanceField.get(instance);
if (value == null) {
value = new ConfigBlock();
instanceField.set(instance, value);
}
instance = value.get(split[1]);
if (instance == null) {
instance = found.getDeclaredConstructor().newInstance();
value.put(split[1], instance);
}
clazz = found;
split = Arrays.copyOfRange(split, 2, split.length);
continue;
} catch (NoSuchFieldException ignored) {
}
if (found != null) {
split = Arrays.copyOfRange(split, 1, split.length);
clazz = found;
instance = clazz.getDeclaredConstructor().newInstance();
continue;
}
return null;
}
} catch (Throwable e) {
e.printStackTrace();

View File

@ -9,12 +9,28 @@ import java.util.concurrent.ConcurrentHashMap;
public class DBHandler {
private static final Logger LOGGER = LogManagerCompat.getLogger();
/**
* @deprecated Use {@link #dbHandler()} instead.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
public static final DBHandler IMP = new DBHandler();
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static DBHandler INSTANCE;
private final Map<World, RollbackDatabase> databases = new ConcurrentHashMap<>(8, 0.9f, 1);
/**
* Get an instance of the DBHandler.
*
* @return an instance of the DBHandler.
* @since 2.0.0
*/
public static DBHandler dbHandler() {
if (INSTANCE == null) {
INSTANCE = new DBHandler();
}
return INSTANCE;
}
public RollbackDatabase getDatabase(World world) {
RollbackDatabase database = databases.get(world);
if (database != null) {

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