Commits vergleichen

..

1 Commits

Autor SHA1 Nachricht Datum
Maddy Miller
daa4d22c6b
Add a //pos command to set multiple positions at once
- API-breaking so blocked
2021-12-29 13:52:20 +00:00
562 geänderte Dateien mit 8401 neuen und 46160 gelöschten Zeilen

Datei anzeigen

@ -7,8 +7,8 @@ body:
attributes: attributes:
value: | value: |
Thanks for taking the time to fill out this bug report for FastAsyncWorldEdit! Fill out the following form to your best ability to help us fix the problem. Thanks for taking the time to fill out this bug report for FastAsyncWorldEdit! Fill out the following form to your best ability to help us fix the problem.
Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/fastasyncworldedit-documentation/). Only use this if you're absolutely sure that you found a bug and can reproduce it. For anything else, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki).
Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://github.com/IntellectualSites/FastAsyncWorldEdit/security/policy) GitHub form! Do NOT use the public issue tracker to report security vulnerabilities! They are disclosed using [this](https://forms.gle/btgdRn9yhGtzEiGW8) form!
- type: dropdown - type: dropdown
attributes: attributes:
@ -18,6 +18,8 @@ body:
options: options:
- Paper - Paper
- Spigot - Spigot
- Tuinity
- Purpur
validations: validations:
required: true required: true
@ -27,11 +29,10 @@ body:
description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first.
multiple: false multiple: false
options: options:
- '1.20.1' - '1.18.1'
- '1.20'
- '1.19.4'
- '1.18.2'
- '1.17.1' - '1.17.1'
- '1.16.5'
- '1.15.2'
validations: validations:
required: true required: true

Datei anzeigen

@ -4,5 +4,5 @@ contact_links:
url: https://discord.gg/intellectualsites url: https://discord.gg/intellectualsites
about: Our support Discord, please ask questions and seek support here. about: Our support Discord, please ask questions and seek support here.
- name: FastAsyncWorldEdit Wiki - name: FastAsyncWorldEdit Wiki
url: https://intellectualsites.github.io/fastasyncworldedit-documentation/ url: https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki
about: Look at the wiki page for answers for setup instructions command syntax and more. about: Look at the wiki page for answers for setup instructions command syntax and more.

Datei anzeigen

@ -7,7 +7,7 @@ body:
attributes: attributes:
value: | value: |
Thanks for taking the time to fill out this feature request for FastAsyncWorldEdit! Fill out the following form to your best ability to help us understand your feature request and greately improve the change of it getting added. Thanks for taking the time to fill out this feature request for FastAsyncWorldEdit! Fill out the following form to your best ability to help us understand your feature request and greately improve the change of it getting added.
For anything else than a feature request, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://intellectualsites.github.io/fastasyncworldedit-documentation/). For anything else than a feature request, use: [our Discord server](https://discord.gg/intellectualsites) or [the wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki).
- type: textarea - type: textarea
attributes: attributes:

35
.github/renovate.json vendored
Datei anzeigen

@ -1,35 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":semanticCommitsDisabled"
],
"automerge": true,
"ignoreDeps": [
"guava",
"com.google.guava:guava",
"rhino-runtime",
"org.antlr",
"antlr4-runtime",
"fastutil",
"it.unimi.dsi:fastutil",
"auto-value-annotations",
"auto-value",
"com.google.code.gson:gson",
"net.fabricmc:fabric-loader",
"net.fabricmc.fabric-api:fabric-api",
"com.github.luben:zstd-jni",
"org.jetbrains.kotlin.jvm",
"log4j",
"org.apache.logging.log4j:log4j-api",
"org.apache.logging.log4j:log4j-bom",
"org.apache.logging.log4j:log4j-slf4j-impl",
"org.apache.logging.log4j:log4j-core",
"org.bstats:bstats-sponge",
"org.spongepowered:spongeapi",
"org.yaml:snakeyaml"
],
"labels": ["Renovate"],
"rebaseWhen": "conflicted",
"schedule": ["on the first day of the month"]
}

Datei anzeigen

@ -1,28 +0,0 @@
name: Announce release on discord
#on:
# workflow_run:
# workflows: ["Upload release assets"]
# types:
# - completed
jobs:
send_announcement:
runs-on: ubuntu-latest
steps:
- name: send custom message with args
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
DISCORD_USERNAME: FastAsyncWorldEdit Release
DISCORD_AVATAR: https://raw.githubusercontent.com/IntellectualSites/Assets/main/plugins/FastAsyncWorldEdit/FastAsyncWorldEdit.png
uses: Ilshidur/action-discord@0.3.2
with:
args: |
"<@&525015715300900875> <@&706463154804097105> <@&671372968462516240>"
""
"<:fawe:730750370984493106> **FastAsyncWorldEdit ${{ github.event.release.tag_name }} has been released!**"
""
"Click here to view changelog: https://github.com/IntellectualSites/FastAsyncWorldEdit/releases/tag/${{ github.event.release.tag_name }}"
""
"The download is available at:"
"- Spigot: <https://www.spigotmc.org/resources/13932/>"
"- Modrinth: <https://modrinth.com/plugin/fastasyncworldedit/version/${{ github.event.release.tag_name }}>"
"- CurseForge: <https://www.curseforge.com/minecraft/bukkit-plugins/fawe>"

Datei anzeigen

@ -1,27 +0,0 @@
name: Build PR
on: [pull_request]
jobs:
build_pr:
if: github.repository_owner == 'IntellectualSites'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
cache: gradle
java-version: 17
- name: Build on ${{ matrix.os }}
run: ./gradlew build -s
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: FastAsyncWorldEdit-SNAPSHOT
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar

Datei anzeigen

@ -1,19 +1,17 @@
name: Build name: build
on:
push: on: [pull_request, push]
branches:
- main
jobs: jobs:
build: build:
if: github.repository_owner == 'IntellectualSites'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v3 uses: actions/checkout@v2.4.0
- name: Validate Gradle Wrapper - name : Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses : gradle/wrapper-validation-action@v1.0.4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v3 uses: actions/setup-java@v2.4.0
with: with:
distribution: temurin distribution: temurin
cache: gradle cache: gradle
@ -29,50 +27,21 @@ jobs:
echo "STATUS=release" >> $GITHUB_ENV echo "STATUS=release" >> $GITHUB_ENV
fi fi
- name: Publish Release - name: Publish Release
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}} if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18'}}
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository run: ./gradlew publishToSonatype closeSonatypeStagingRepository
env: env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }} ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
- name: Publish Snapshot - name: Publish Snapshot
if: ${{ runner.os == 'Linux' && env.STATUS != 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main' }} if: ${{ runner.os == 'Linux' && env.STATUS != 'release' && github.event_name == 'push' && github.ref == 'refs/heads/major/2.0.0/1.18' }}
run: ./gradlew publishToSonatype run: ./gradlew publishToSonatype
env: env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }} ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
- name: Publish core javadoc
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
uses: cpina/github-action-push-to-another-repository@main
env:
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
with:
source-directory: 'worldedit-core/build/docs/javadoc'
destination-github-username: 'IntellectualSites'
destination-repository-name: 'fastasyncworldedit-javadocs'
user-email: ${{ secrets.USER_EMAIL }}
target-branch: main
target-directory: worldedit-core
- name: Publish bukkit javadoc
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
uses: cpina/github-action-push-to-another-repository@main
env:
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
with:
source-directory: 'worldedit-bukkit/build/docs/javadoc'
destination-github-username: 'IntellectualSites'
destination-repository-name: 'fastasyncworldedit-javadocs'
user-email: ${{ secrets.USER_EMAIL }}
target-branch: main
target-directory: worldedit-bukkit
- name: Archive Artifacts - name: Archive Artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v2.3.1
with: with:
name: FastAsyncWorldEdit-Bukkit-SNAPSHOT name: FastAsyncWorldEdit-Bukkit-SNAPSHOT
path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar path: worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar
- name: Publish to Modrinth
if: ${{ runner.os == 'Linux' && env.STATUS == 'release' && github.event_name == 'push' && github.ref == 'refs/heads/main'}}
run: ./gradlew modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}

Datei anzeigen

@ -1,36 +0,0 @@
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ['java']
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
cache: gradle
java-version: 17
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

Datei anzeigen

@ -1,17 +1,14 @@
name: draft release name: draft release
on: on:
push: push:
branches: branches:
- main - main
pull_request:
types: [opened, reopened, synchronize]
pull_request_target:
types: [opened, reopened, synchronize]
jobs: jobs:
update_release_draft: update_release_draft:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@v5 - uses: release-drafter/release-drafter@v5.15.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Datei anzeigen

@ -1,26 +0,0 @@
name: Upload release assets
on:
release:
types: [published]
jobs:
upload_asset:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
cache: gradle
java-version: 17
- name: Clean Build
run: ./gradlew clean build --no-daemon
- name: Upload Release Assets
uses: AButler/upload-release-assets@v2.0
with:
files: 'worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-*.jar'
repo-token: ${{ secrets.GITHUB_TOKEN }}
release-tag: ${{ github.event.release.tag_name }}

8
.gitignore vendored
Datei anzeigen

@ -2,8 +2,7 @@
.project .project
.settings .settings
eclipse eclipse
/.idea/* .idea
!/.idea/icon.svg
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
@ -24,6 +23,7 @@ logs/
worldedit-bukkit/src/main/java/ignore/* worldedit-bukkit/src/main/java/ignore/*
todo.txt todo.txt
mvn/* mvn/*
docs/
*.sh *.sh
# i18n # i18n
worldedit-core/src/main/resources/lang/* worldedit-core/src/main/resources/lang/*
@ -31,7 +31,3 @@ worldedit-core/src/main/resources/lang/*
**/*.eml **/*.eml
/worldedit-core/FastAsyncWorldEdit.worldedit-core.eml /worldedit-core/FastAsyncWorldEdit.worldedit-core.eml
/worldedit-core/.factorypath /worldedit-core/.factorypath
.DS_Store
### Run server ignore
run-*

Datei anzeigen

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
id="svg2"
xml:space="preserve"
width="512"
height="512"
viewBox="0 0 512 512.00001"
sodipodi:docname="icon.svg"
inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18">
<path
d="M 0,2500 H 3000 V 0 H 0 Z"
id="path16" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18-2"><path
d="M 0,2500 H 3000 V 0 H 0 Z"
id="path16-1" /></clipPath></defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="872"
id="namedview4"
inkscape:pagecheckerboard="0"
showgrid="false"
width="512px"
inkscape:snap-others="false"
inkscape:zoom="0.2263301"
inkscape:cx="797.50773"
inkscape:cy="547.87234"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="0"
inkscape:current-layer="g10" />
<g
id="g10"
inkscape:groupmode="layer"
inkscape:label="FastAsyncWorldEdit"
transform="matrix(1.3333333,0,0,-1.3333333,0,3333.3333)">
<g
id="g12"
transform="matrix(0.17875858,0,0,0.17875858,-78.817913,2093.6589)"><g
id="g14"
clip-path="url(#clipPath18-2)"><g
id="g20"
transform="translate(1643.0798,2025.9724)"><path
d="m 0,0 c 34.839,11.026 70.869,18.313 107.28,21.408 18.861,-48.96 46.604,-93.992 77.514,-136.19 49.794,-66.487 110.495,-124.616 178.34,-172.506 78.156,-55.366 165.481,-97.254 256.496,-126.783 83.229,-27.124 169.601,-44.008 256.592,-53.295 -1.047,-153.146 -64.344,-303.076 -167.124,-415.762 -47.77,-52.914 -103.208,-99.136 -164.838,-135.047 -91.873,-53.843 -197.557,-83.896 -304.076,-85.705 -10.764,101.16 -31.91,201.534 -67.273,297.051 -28.243,76.537 -65.678,149.835 -112.853,216.465 -47.865,67.583 -105.685,128.332 -172.125,177.888 -42.102,31.22 -87.348,58.939 -136.404,77.823 3.834,48.628 15.479,96.636 33.625,141.906 19.169,46.769 46.96,90.968 85.752,123.926 C -91.706,-36.816 -46.722,-14.717 0,0"
style="fill:#4c8fcc;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path22" /></g><g
id="g24"
transform="translate(1887.3362,1969.7008)"><path
d="m 0,0 c 20.837,19.313 56.319,19.718 77.228,0.333 32.243,-32.053 64.272,-64.296 96.492,-96.373 17.313,-17.384 20.766,-46.27 8.93,-67.631 -9.073,-15.431 -23.813,-26.314 -35.744,-39.388 -37.339,25.29 -72.917,53.105 -106.637,83.015 -17.122,17.074 -36.316,32.076 -51.771,50.794 -8.525,10.74 -20.432,18.813 -26.457,31.458 C -25.242,-25.242 -12.788,-12.431 0,0"
style="fill:#062f4c;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path26" /></g><g
id="g28"
transform="translate(1463.3822,1497.8577)"><path
d="m 0,0 c -4.644,-0.786 -9.097,-2.786 -12.383,-6.168 -292.384,-292.645 -585.053,-585.029 -877.484,-877.627 -6.74,-6.382 -14.741,-13.145 -14.717,-23.337 -1.262,-12.383 8.668,-21.242 17.384,-28.291 9.882,-6.882 24.552,-4.215 32.481,4.525 293.718,293.693 587.411,587.387 881.104,881.104 10.74,9.049 12.241,27.219 1.929,37.101 C 21.48,-4.406 11.264,2.715 0,0 M -994.266,-946.234 C -647.088,-599.055 -299.885,-251.901 47.27,95.326 84.134,65.44 116.592,30.505 147.502,-5.382 c 23.266,-26.814 43.579,-55.986 64.749,-84.419 -346.679,-346.584 -693.215,-693.286 -1039.941,-1039.822 -20.623,-21.98 -58.439,-23.599 -80.514,-2.953 -32.172,32.149 -64.321,64.345 -96.493,96.493 -16.503,16.741 -19.932,44.007 -9.882,64.963 4.572,9.907 12.692,17.384 20.313,24.886"
style="fill:#062f4c;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path30" /></g><g
id="g32"
transform="translate(1827.8735,1911.1907)"><path
d="M 0,0 C 7.859,6.168 14.288,13.883 21.504,20.718 27.529,8.073 39.435,0 47.961,-10.74 c 15.455,-18.717 34.648,-33.72 51.77,-50.794 33.721,-29.91 69.298,-57.725 106.638,-83.015 -9.383,-9.263 -18.67,-18.67 -28.029,-27.957 C 110.495,-124.617 49.794,-66.488 0,0"
style="fill:#081d2d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path34" /></g><g
id="g36"
transform="translate(1531.0129,1613.4966)"><path
d="m 0,0 c 66.44,-49.556 124.26,-110.305 172.125,-177.888 -9.145,-9.192 -18.36,-18.336 -27.505,-27.552 -21.17,28.433 -41.483,57.605 -64.749,84.419 C 48.961,-85.134 16.503,-50.199 -20.361,-20.313 -13.574,-13.55 -6.811,-6.763 0,0"
style="fill:#081d2d;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path38" /></g><g
id="g40"
transform="translate(2519.302,1558.6062)"><path
d="M 0,0 C 21.408,-2.334 42.865,-3.763 64.321,-5.596 73.179,-84.086 63.178,-164.123 40.126,-239.47 3.072,-360.657 -72.393,-468.319 -168.696,-549.976 c -101.446,-87.038 -230.349,-142.429 -363.943,-152.121 -32.72,-2.548 -65.726,-2.453 -98.279,1.786 -0.857,21.313 -3.072,42.555 -5.12,63.797 106.518,1.81 212.203,31.862 304.076,85.705 61.63,35.911 117.068,82.133 164.838,135.047 C -64.344,-303.076 -1.048,-153.145 0,0"
style="fill:#6fc4ee;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path42" /></g><g
id="g44"
transform="translate(1463.3822,1497.8577)"><path
d="m 0,0 c 11.264,2.715 21.48,-4.406 28.314,-12.693 10.312,-9.882 8.811,-28.052 -1.929,-37.101 -293.693,-293.717 -587.386,-587.411 -881.104,-881.104 -7.929,-8.74 -22.599,-11.407 -32.481,-4.525 -8.716,7.049 -18.646,15.908 -17.384,28.291 -0.024,10.192 7.977,16.955 14.717,23.337 292.431,292.598 585.1,584.982 877.484,877.627 C -9.097,-2.786 -4.644,-0.786 0,0"
style="fill:#105677;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path46" /></g></g></g></g>
</svg>

Vorher

Breite:  |  Höhe:  |  Größe: 6.3 KiB

13
.whitesource Normale Datei
Datei anzeigen

@ -0,0 +1,13 @@
{
"scanSettings": {
"baseBranches": ["main"]
},
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure",
"displayMode": "diff"
},
"issueSettings": {
"minSeverityLevel": "LOW"
},
"enableRenovate": "true"
}

Datei anzeigen

@ -1,54 +0,0 @@
: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.

Datei anzeigen

@ -1,14 +1,12 @@
:toc: Compiling
:toclevels: 2 =========
= Compiling
You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed, You can compile FastAsyncWorldEdit as long as you have some version of Java greater than or equal to 17 installed. Gradle will download JDK 17 specifically if needed,
but it needs some version of Java to bootstrap from. but it needs some version of Java to bootstrap from.
Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 17. Note that if you have JRE 8 installed, Gradle will currently attempt to use that to compile, which will not work. It is easiest to uninstall JRE 8 and replace it with JDK 16.
You can get the JDK 17 link:https://adoptium.net/[here] from Adoptium. 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: The build process uses Gradle, which you do *not* need to download. FastAsyncWorldEdit is a multi-module project with three active modules:
@ -16,19 +14,23 @@ The build process uses Gradle, which you do *not* need to download. FastAsyncWor
* `worldedit-bukkit` is the Bukkit plugin * `worldedit-bukkit` is the Bukkit plugin
* `worldedit-cli` is the command line interface * `worldedit-cli` is the command line interface
== To compile... ## To compile...
=== On Windows ### 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". 1. Shift + right-click the folder with FastAsyncWorldEdit's files and click "Open command prompt".
2. `gradlew clean build` 2. `gradlew clean build`
=== On Linux, BSD, or Mac OS X ### On Linux, BSD, or Mac OS X
1. In your terminal, navigate to the folder with FastAsyncWorldEdit's files (`cd /folder/of/fawe/files`) 1. In your terminal, navigate to the folder with FastAsyncWorldEdit's files (`cd /folder/of/fawe/files`)
2. `./gradlew clean build` 2. `./gradlew clean build`
== Then you will find... ## Then you will find...
You will find: You will find:
@ -40,10 +42,10 @@ If you want to use FastAsyncWorldEdit, use the `FastAsyncWorldEdit-<identifier>`
(The `-#` version includes FastAsyncWorldEdit + necessary libraries.) (The `-#` version includes FastAsyncWorldEdit + necessary libraries.)
== Other commands ## Other commands
* `gradlew idea` will generate an link:https://www.jetbrains.com/idea/[IntelliJ IDEA] module for each folder. * `gradlew idea` will generate an [IntelliJ IDEA](https://www.jetbrains.com/idea/) module for each folder.
_Possibly broken_: _Possibly broken_:
* `gradlew eclipse` will generate an link:https://www.eclipse.org/downloads/[Eclipse] project for each folder. * `gradlew eclipse` will generate an [Eclipse](https://www.eclipse.org/downloads/) project for each folder.

36
Jenkinsfile vendored
Datei anzeigen

@ -1,36 +0,0 @@
pipeline {
agent any
options {
disableConcurrentBuilds()
}
stages {
stage('Build') {
steps {
withEnv([
"PATH+JAVA=${tool 'Temurin-17.0.7_7'}/bin"
]) {
sh './gradlew clean build'
}
}
}
stage('Archive artifacts') {
steps {
sh 'rm -rf artifacts'
sh 'mkdir artifacts'
sh 'cp worldedit-bukkit/build/libs/FastAsyncWorldEdit*.jar artifacts/'
sh 'cp worldedit-cli/build/libs/FastAsyncWorldEdit*.jar artifacts/'
archiveArtifacts artifacts: 'artifacts/*.jar', followSymlinks: false
}
}
stage('Fingerprint artifacts') {
steps {
fingerprint 'worldedit-bukkit/build/libs/FastAsyncWorldEdit*.jar'
}
}
stage('Publish JUnit test results') {
steps {
junit 'worldedit-core/build/test-results/test/*.xml,worldedit-bukkit/build/test-results/test/*.xml'
}
}
}
}

109
README.md
Datei anzeigen

@ -1,95 +1,48 @@
# FastAsyncWorldEdit <p align="center">
[![Join us on Discord](https://img.shields.io/discord/268444645527126017.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/intellectualsites) <img src="fawe-logo.png" width="150">
[![bStats Servers](https://img.shields.io/bstats/servers/1403)](https://bstats.org/plugin/bukkit/FastAsyncWorldEdit/1403) </p>
[![Crowdin](https://badges.crowdin.net/e/4a5819fae3fd88234a8ea13bfbb072bb/localized.svg)](https://intellectualsites.crowdin.com/fastasyncworldedit)
## What is FAWE and why should I use it? ---
FAWE is designed for efficient world editing. FastAsyncWorldEdit is a fork of WorldEdit that has huge speed and memory improvements and considerably more features
* Simple to set up and use
* Extremely configurable
* Uses minimal CPU/Memory
* Safe for many players to use
* Insanely fast, when using the slowest mode
FastAsyncWorldEdit is a fork of WorldEdit that has huge speed and memory improvements and considerably more features. **A Minecraft Map Editor... that runs in-game!**
If you use other plugins which depend on WorldEdit, simply having FAWE installed will boost their performance.
## Downloads * With selections, schematics, copy and paste, brushes, and scripting!
* Use it in creative, survival in single player or on your server.
* Use it on your Minecraft server to fix grieving and mistakes.
Downloads are available either on SpigotMC, Modrinth or on CurseForge. Java Edition required. FastAsyncWorldEdit is compatible with Bukkit, Spigot and Paper.
- [SpigotMC](https://www.spigotmc.org/resources/13932/)
- [Modrinth](https://modrinth.com/plugin/fastasyncworldedit/)
- [CurseForge](https://dev.bukkit.org/projects/fawe)
Snapshots are available on [Jenkins](https://ci.athion.net/job/FastAsyncWorldEdit/). ## Download FastAsyncWorldEdit
* Spigot: https://www.spigotmc.org/resources/fast-async-worldedit.13932/
* Older, unsupported, versions: https://intellectualsites.github.io/download/fawe.html
## Features ## Links
* Over 200 Commands * [Discord](https://discord.gg/intellectualsites)
* Style and translate messages and commands * [Wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/wiki)
* (No setup required) Clipboard web integration (Clipboard) * [Report Issue](https://github.com/IntellectualSites/FastAsyncWorldEdit/issues)
* Unlimited //undo, per world history, instant lookups/rollback and cross server clipboards * [Crowdin (Translations)](https://intellectualsites.crowdin.com/fastasyncworldedit)
* Advanced per player limits (entity, tiles, memory, changes, iterations, regions, inventory) * [JavaDocs for the -bukkit module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Bukkit/latest/index.html)
* Visualization, targeting modes/masks and scroll actions * [JavaDocs for the -core module](https://javadoc.io/doc/com.fastasyncworldedit/FastAsyncWorldEdit-Core/latest/index.html)
* Adds lots of powerful new //brushes and //tools.
* Adds a lot more mask functionality. (new mask syntax, patterns, expressions, source masks)
* Adds a lot more pattern functionality. (a lot of new pattern syntax and patterns)
* Adds edit transforms (apply transforms to a source, e.g. on //paste)
* Adds support for new formats (e.g. Structure Blocks)
* Instant copying of arbitrary size with `//lazycopy`
* Auto repair partially corrupt schematic files
* Biome mixing, in-game world painting, dynamic view distance, vanilla cui, off axis rotation, image importing, cave generation,
multi-clipboards, interactive messages, schematic visualization, lag prevention, persistent brushes + A LOT MORE
### Performance ## Edit The Code
There are several placement modes, each supporting higher throughput than the previous. All editing is processed
asynchronously, with
certain tasks being broken up on the main thread. The default mode is chunk placement.
* Blocks (Bukkit-API) - Only used if chunk placement isn't supported. Still faster than any other plugin on spigot.
* Chunks (NMS) - Places entire chunk sections
* World (CFI) - Used to generate new worlds / regions
### Protection Plugins
The following plugins are supported with Bukkit:
* [WorldGuard](https://dev.bukkit.org/projects/worldguard)
* [PlotSquared](https://www.spigotmc.org/resources/77506/)
### Logging and Rollback
By default you can use `//inspect` and `//history rollback` to search and restore changes. To reduce disk usage, increase the
compression level and buffer size. To bypass logging use `//fast`.
### Developer API
FAWE maintains API compatibility with WorldEdit, so you can use the normal WorldEdit API asynchronously.
FAWE also has some asynchronously wrappers for the Bukkit API.
The wiki has examples for various things like reading NBT, modifying world files, pasting schematics, splitting up tasks, lighting etc.
If you need help with anything, hop on discord (link on the left bar).
## Documentation
* [Wiki](https://intellectualsites.github.io/fastasyncworldedit-documentation/)
* [Javadocs](https://intellectualsites.github.io/fastasyncworldedit-javadocs/)
## Contributing
Want to add new features to FastAsyncWorldEdit or fix bugs yourself? You can get the game running, with FastAsyncWorldEdit, from the code here: Want to add new features to FastAsyncWorldEdit or fix bugs yourself? You can get the game running, with FastAsyncWorldEdit, from the code here:
For additional information about compiling FastAsyncWorldEdit, read the [compiling documentation](https://github.com/IntellectualSites/FastAsyncWorldEdit/blob/main/COMPILING.adoc). For additional information about compiling FastAsyncWorldEdit, see [COMPILING.md](COMPILING.md).
## Special thanks ## Submitting Your Changes
FastAsyncWorldEdit is open source (specifically licensed under GPL v3), so note that your contributions will also be open source. The best way to submit a change is to create a fork on GitHub, put your changes there, and then create a "pull request" on our FastAsyncWorldEdit repository.
<a href="https://jb.gg/OpenSourceSupport"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg" width="150"> Please read [CONTRIBUTING.md](https://github.com/IntellectualSites/.github/blob/main/CONTRIBUTING.md) for important guidelines to follow.
## YourKit
<a href="https://www.yourkit.com">
<img src="https://www.yourkit.com/images/yklogo.png">
</a> </a>
</br>
[JetBrains](https://jb.gg/OpenSourceSupport), creators of the IntelliJ IDEA, supports us with their Open Source Licenses.
<a href="https://yourkit.com/"><img src="https://www.yourkit.com/images/yklogo.png" width="200">
</a>
Thank you to YourKit for supporting our product by providing us with their innovative and intelligent tools Thank you to YourKit for supporting our product by providing us with their innovative and intelligent tools
for monitoring and profiling Java and .NET applications. for monitoring and profiling Java and .NET applications.
YourKit is the creator of [YourKit Java Profiler](https://www.yourkit.com/java/profiler/), [YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/), and [YourKit YouMonitor](https://www.yourkit.com/youmonitor/). YourKit is the creator of <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>, <a href="https://www.yourkit.com/.net/profiler/">YourKit .NET Profiler</a>, and <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>

Datei anzeigen

@ -1,23 +1,11 @@
import org.ajoberstar.grgit.Grgit 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.TestExceptionFormat.FULL
import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED
import java.net.URI import java.net.URI
import java.time.format.DateTimeFormatter
import xyz.jpenilla.runpaper.task.RunServer
plugins { plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.3.0" id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
id("xyz.jpenilla.run-paper") version "2.1.0"
}
if (!File("$rootDir/.git").exists()) {
logger.lifecycle("""
**************************************************************************************
You need to fork and clone this repository! Don't download a .zip file.
If you need assistance, consult the GitHub docs: https://docs.github.com/get-started/quickstart/fork-a-repo
**************************************************************************************
""".trimIndent()
).also { kotlin.system.exitProcess(1) }
} }
logger.lifecycle(""" logger.lifecycle("""
@ -25,7 +13,7 @@ logger.lifecycle("""
You are building FastAsyncWorldEdit! You are building FastAsyncWorldEdit!
If you encounter trouble: If you encounter trouble:
1) Read COMPILING.adoc if you haven't yet 1) Read COMPILING.md if you haven't yet
2) Try running 'build' in a separate Gradle run 2) Try running 'build' in a separate Gradle run
3) Use gradlew and not gradle 3) Use gradlew and not gradle
4) If you still need help, ask on Discord! https://discord.gg/intellectualsites 4) If you still need help, ask on Discord! https://discord.gg/intellectualsites
@ -34,7 +22,7 @@ logger.lifecycle("""
******************************************* *******************************************
""") """)
var rootVersion by extra("2.7.1") var rootVersion by extra("2.0.0")
var snapshot by extra("SNAPSHOT") var snapshot by extra("SNAPSHOT")
var revision: String by extra("") var revision: String by extra("")
var buildNumber by extra("") var buildNumber by extra("")
@ -83,29 +71,9 @@ allprojects {
} }
applyCommonConfiguration() applyCommonConfiguration()
val supportedVersions = listOf("1.16.5", "1.17", "1.17.1", "1.18.2", "1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20", "1.20.1")
tasks {
supportedVersions.forEach {
register<RunServer>("runServer-$it") {
minecraftVersion(it)
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
.toTypedArray())
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true")
group = "run paper"
runDirectory.set(file("run-$it"))
}
}
runServer {
minecraftVersion("1.20.1")
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
.toTypedArray())
}
}
nexusPublishing { nexusPublishing {
this.repositories { repositories {
sonatype { sonatype {
nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/")) nexusUrl.set(URI.create("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/")) snapshotRepositoryUrl.set(URI.create("https://s01.oss.sonatype.org/content/repositories/snapshots/"))

Datei anzeigen

@ -12,6 +12,13 @@ repositories {
name = "EngineHub" name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/") 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 -> val properties = Properties().also { props ->
@ -22,9 +29,9 @@ val properties = Properties().also { props ->
dependencies { dependencies {
implementation(gradleApi()) implementation(gradleApi())
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.0") implementation("org.ajoberstar.grgit:grgit-gradle:4.1.1")
implementation("com.github.johnrengelman:shadow:8.1.1") implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.1")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.5") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.3.3")
} }
kotlin { kotlin {

Datei anzeigen

@ -1,3 +1,4 @@
import io.papermc.paperweight.userdev.attribute.Obfuscation
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies

Datei anzeigen

@ -10,7 +10,12 @@ fun Project.applyCommonConfiguration() {
version = rootProject.version version = rootProject.version
repositories { repositories {
mavenLocal()
mavenCentral() mavenCentral()
maven {
name = "IntellectualSites"
url = uri("https://mvn.intellectualsites.com/content/groups/public/")
}
maven { maven {
name = "EngineHub" name = "EngineHub"
url = uri("https://maven.enginehub.org/repo/") url = uri("https://maven.enginehub.org/repo/")
@ -19,6 +24,10 @@ fun Project.applyCommonConfiguration() {
name = "OSS Sonatype Snapshots" name = "OSS Sonatype Snapshots"
url = uri("https://oss.sonatype.org/content/repositories/snapshots/") url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
} }
maven {
name = "OSS Sonatype Releases"
url = uri("https://oss.sonatype.org/content/repositories/releases/")
}
maven { maven {
name = "Athion" name = "Athion"
url = uri("https://ci.athion.net/plugin/repository/tools/") url = uri("https://ci.athion.net/plugin/repository/tools/")
@ -45,15 +54,15 @@ fun Project.applyCommonConfiguration() {
continue continue
} }
add(conf.name, "com.google.guava:guava") { add(conf.name, "com.google.guava:guava") {
version { require("31.1-jre") } version { require("31.0.1-jre") }
because("Mojang provides Guava") because("Mojang provides Guava")
} }
add(conf.name, "com.google.code.gson:gson") { add(conf.name, "com.google.code.gson:gson") {
version { require("2.10") } version { require("2.8.8") }
because("Mojang provides Gson") because("Mojang provides Gson")
} }
add(conf.name, "it.unimi.dsi:fastutil") { add(conf.name, "it.unimi.dsi:fastutil") {
version { require("8.5.9") } version { require("8.5.6") }
because("Mojang provides FastUtil") because("Mojang provides FastUtil")
} }
} }

Datei anzeigen

@ -1,6 +1,7 @@
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.attributes.java.TargetJvmVersion import org.gradle.api.attributes.java.TargetJvmVersion
import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.plugins.quality.CheckstyleExtension
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test import org.gradle.api.tasks.testing.Test
@ -40,11 +41,11 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
dependencies { dependencies {
"compileOnly"("com.google.code.findbugs:jsr305:3.0.2") "compileOnly"("com.google.code.findbugs:jsr305:3.0.2")
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.10.0") "testImplementation"("org.junit.jupiter:junit-jupiter-api:5.8.1")
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.10.0") "testImplementation"("org.junit.jupiter:junit-jupiter-params:5.8.1")
"testImplementation"("org.mockito:mockito-core:5.4.0") "testImplementation"("org.mockito:mockito-core:3.12.4")
"testImplementation"("org.mockito:mockito-junit-jupiter:5.4.0") "testImplementation"("org.mockito:mockito-junit-jupiter:3.12.4")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.10.0") "testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.8.1")
} }
// Java 8 turns on doclint which we fail // Java 8 turns on doclint which we fail
@ -58,15 +59,15 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
) )
options.encoding = "UTF-8" options.encoding = "UTF-8"
links( links(
"https://jd.advntr.dev/api/latest/", "https://javadoc.io/doc/com.google.code.findbugs/jsr305/3.0.2/",
"https://logging.apache.org/log4j/2.x/log4j-api/apidocs/", "https://jd.adventure.kyori.net/api/4.9.3/",
"https://javadoc.io/doc/org.apache.logging.log4j/log4j-api/2.14.1/",
"https://www.antlr.org/api/Java/", "https://www.antlr.org/api/Java/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/", "https://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://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/",
"https://jd.papermc.io/paper/1.20/", "https://papermc.io/javadocs/paper/1.18/",
"https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" "https://ci.athion.net/job/FastAsyncWorldEdit-1.17-Core-Javadocs/javadoc/" // needed for other module linking
) )
docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}"
} }
} }

Datei anzeigen

@ -204,7 +204,7 @@ fun Project.applyLibrariesConfiguration() {
from(libsComponent) from(libsComponent)
group = "com.fastasyncworldedit" group = "com.fastasyncworldedit"
artifactId = "FastAsyncWorldEdit-Libs-${project.name.replaceFirstChar(Char::titlecase)}" artifactId = "FastAsyncWorldEdit-Libs-${project.name.capitalize()}"
version = version version = version
pom { pom {
@ -223,8 +223,8 @@ fun Project.applyLibrariesConfiguration() {
developers { developers {
developer { developer {
id.set("NotMyFault") id.set("NotMyFault")
name.set("Alexander Brandes") name.set("NotMyFault")
email.set("contact(at)notmyfault.dev") email.set("contact@notmyfault.dev")
organization.set("IntellectualSites") organization.set("IntellectualSites")
} }
developer { developer {

Datei anzeigen

@ -84,8 +84,8 @@ fun Project.applyPlatformAndCoreConfiguration() {
developers { developers {
developer { developer {
id.set("NotMyFault") id.set("NotMyFault")
name.set("Alexander Brandes") name.set("NotMyFault")
email.set("contact(at)notmyfault.dev") email.set("contact@notmyfault.dev")
organization.set("IntellectualSites") organization.set("IntellectualSites")
} }
developer { developer {

BIN
fawe-logo.png Normale Datei

Binäre Datei nicht angezeigt.

Nachher

Breite:  |  Höhe:  |  Größe: 17 KiB

Datei anzeigen

@ -1,83 +1,96 @@
[versions] [versions]
# Minecraft expectations # Minecraft expectations
paper = "1.20.1-R0.1-SNAPSHOT" fastutil = "8.5.6"
fastutil = "8.5.9" log4j = "2.17.0"
guava = "31.1-jre" guava = "31.0.1-jre"
log4j = "2.19.0" gson = "2.8.9"
gson = "2.10"
snakeyaml = "2.0" # Platform expectations
paper = "1.18.1-R0.1-SNAPSHOT"
# Plugins # Plugins
vault = "1.7.1"
dummypermscompat = "1.10" dummypermscompat = "1.10"
worldguard-bukkit = "7.0.9" worldguard-bukkit = "7.0.6"
mapmanager = "1.8.0-SNAPSHOT" mapmanager = "1.8.0-SNAPSHOT"
griefprevention = "16.18.1" griefprevention = "16.17.1"
griefdefender = "2.1.0-SNAPSHOT" griefdefender = "920a610"
mcore = "7.0.1"
residence = "4.5._13.1" residence = "4.5._13.1"
towny = "0.99.5.10" towny = "0.97.5.0"
plotsquared = "7.0.0-rc.4" protocollib = "4.7.0"
plotsquaredV6 = "6.2.0"
redprotect = "1.9.6"
# Third party # Third party
bstats = "3.0.2" flow-math = "1.0.3"
paperlib = "1.0.8-SNAPSHOT"
bstats = "2.2.1"
serverlib = "2.3.1"
paster = "1.1.3"
sparsebitset = "1.2" sparsebitset = "1.2"
parallelgzip = "1.0.5" parallelgzip = "1.0.5"
adventure = "4.14.0" adventure = "4.9.3"
adventure-bukkit = "4.3.0"
checkerqual = "3.37.0"
truezip = "6.8.4" truezip = "6.8.4"
auto-value = "1.10.2" auto-value = "1.9"
findbugs = "3.0.2" findbugs = "3.0.2"
rhino-runtime = "1.7.14" rhino-runtime = "1.7.13"
zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs
antlr4 = "4.13.0" antlr4 = "4.9.3"
json-simple = "1.1.1" json-simple = "1.1.1"
jlibnoise = "1.0.0" jlibnoise = "1.0.0"
jchronic = "0.2.4a" jchronic = "0.2.4a"
lz4-java = "1.8.0" lz4-java = "1.8.0"
lz4-stream = "1.0.0" lz4-stream = "1.0.0"
commons-cli = "1.5.0"
paperlib = "1.0.8"
paster = "1.1.5"
vault = "1.7.1"
serverlib = "2.3.1"
## Internal ## Internal
adventure-text-minimessage = "4.2.0-SNAPSHOT"
text-adapter = "3.0.6" text-adapter = "3.0.6"
text = "3.0.4" text = "3.0.4"
piston = "0.5.7" piston = "0.5.7"
# Tests # Tests
mockito = "5.4.0" mockito = "4.2.0"
checker-qual = "3.21.0"
# Gradle plugins # Gradle plugins
pluginyml = "0.6.0" pluginyml = "0.5.1"
minotaur = "2.8.3"
[libraries] [libraries]
# Minecraft expectations # Minecraft expectations
paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" } fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
log4j = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
log4jBom = { group = "org.apache.logging.log4j", name = "log4j-bom", version.ref = "log4j" } log4jBom = { group = "org.apache.logging.log4j", name = "log4j-bom", version.ref = "log4j" }
log4jApi = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml" }
#Platform expectations
paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" }
# Plugins # Plugins
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
dummypermscompat = { group = "com.sk89q", name = "dummypermscompat", version.ref = "dummypermscompat" } dummypermscompat = { group = "com.sk89q", name = "dummypermscompat", version.ref = "dummypermscompat" }
worldguard = { group = "com.sk89q.worldguard", name = "worldguard-bukkit", version.ref = "worldguard-bukkit" } worldguard = { group = "com.sk89q.worldguard", name = "worldguard-bukkit", version.ref = "worldguard-bukkit" }
mapmanager = { group = "com.github.InventivetalentDev", name = "MapManager", version.ref = "mapmanager" } mapmanager = { group = "com.github.InventivetalentDev", name = "MapManager", version.ref = "mapmanager" }
griefprevention = { group = "com.github.TechFortress", name = "GriefPrevention", version.ref = "griefprevention" } griefprevention = { group = "com.github.TechFortress", name = "GriefPrevention", version.ref = "griefprevention" }
griefdefender = { group = "com.griefdefender", name = "api", version.ref = "griefdefender" } griefdefender = { group = "com.github.bloodmc", name = "GriefDefenderApi", version.ref = "griefdefender" }
mcore = { group = "com.massivecraft", name = "mcore", version.ref = "mcore" }
residence = { group = "com.bekvon.bukkit.residence", name = "Residence", version.ref = "residence" } residence = { group = "com.bekvon.bukkit.residence", name = "Residence", version.ref = "residence" }
towny = { group = "com.palmergames.bukkit.towny", name = "towny", version.ref = "towny" } towny = { group = "com.github.TownyAdvanced", name = "Towny", version.ref = "towny" }
plotSquaredCore = { group = "com.intellectualsites.plotsquared", name = "plotsquared-core", version.ref = "plotsquared" } protocollib = { group = "com.comphenix.protocol", name = "ProtocolLib", version.ref = "protocollib" }
plotSquaredBukkit = { group = "com.intellectualsites.plotsquared", name = "plotsquared-bukkit", version.ref = "plotsquared" } plotsquaredV6Bukkit = { group = "com.plotsquared", name = "PlotSquared-Bukkit", version.ref = "plotsquaredV6" }
plotsquaredV6Core = { group = "com.plotsquared", name = "PlotSquared-Core", version.ref = "plotsquaredV6" }
redprotect = { group = "net.fabiozumbi12", name = "redprotect", version.ref = "redprotect" }
# Third Party # Third Party
bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" } flowmath = { group = "com.flowpowered", name = "flow-math", version.ref = "flow-math" }
paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" }
bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" } bstatsBukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
bstatsBase = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" }
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref = "paster" }
sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" } sparsebitset = { group = "com.zaxxer", name = "SparseBitSet", version.ref = "sparsebitset" }
parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" } parallelgzip = { group = "org.anarres", name = "parallelgzip", version.ref = "parallelgzip" }
adventure = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
adventureNbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" } adventureNbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" }
truezip = { group = "de.schlichtherle", name = "truezip", version.ref = "truezip" } truezip = { group = "de.schlichtherle", name = "truezip", version.ref = "truezip" }
autoValueAnnotations = { group = "com.google.auto.value", name = "auto-value-annotations", version.ref = "auto-value" } autoValueAnnotations = { group = "com.google.auto.value", name = "auto-value-annotations", version.ref = "auto-value" }
@ -92,19 +105,11 @@ jlibnoise = { group = "com.sk89q.lib", name = "jlibnoise", version.ref = "jlibno
jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" } jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" }
lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" } lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" }
lz4JavaStream = { group = "net.jpountz", name = "lz4-java-stream", version.ref = "lz4-stream" } lz4JavaStream = { group = "net.jpountz", name = "lz4-java-stream", version.ref = "lz4-stream" }
commonsCli = { group = "commons-cli", name = "commons-cli", version.ref = "commons-cli" }
paperlib = { group = "io.papermc", name = "paperlib", version.ref = "paperlib" }
adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
adventureMiniMessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventure" }
adventureBukkit = { group = "net.kyori", name = "adventure-platform-bukkit", version.ref = "adventure-bukkit" }
paster = { group = "com.intellectualsites.paster", name = "Paster", version.ref = "paster" }
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
serverlib = { group = "dev.notmyfault.serverlib", name = "ServerLib", version.ref = "serverlib" }
checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checkerqual" }
# Internal # Internal
## Text ## Text
adventureTextAdapterBukkit = { group = "net.kyori", name = "text-adapter-bukkit", version.ref = "text-adapter" } adventureTextAdapterBukkit = { group = "net.kyori", name = "text-adapter-bukkit", version.ref = "text-adapter" }
adventureTextMiniMessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "adventure-text-minimessage" }
adventureTextApi = { group = "net.kyori", name = "text-api", version.ref = "text" } adventureTextApi = { group = "net.kyori", name = "text-api", version.ref = "text" }
adventureTextSerializerGson = { group = "net.kyori", name = "text-serializer-gson", version.ref = "text" } adventureTextSerializerGson = { group = "net.kyori", name = "text-serializer-gson", version.ref = "text" }
adventureTextSerializerLegacy = { group = "net.kyori", name = "text-serializer-legacy", version.ref = "text" } adventureTextSerializerLegacy = { group = "net.kyori", name = "text-serializer-legacy", version.ref = "text" }
@ -118,8 +123,8 @@ pistonRuntime = { group = "org.enginehub.piston.core-ap", name = "runtime", vers
# Tests # Tests
mockito = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } mockito = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" }
checkerqual = { group = "org.checkerframework", name = "checker-qual", version.ref = "checker-qual" }
log4jCore = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" } log4jCore = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" }
[plugins] [plugins]
pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" } pluginyml = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" }

Binäre Datei nicht angezeigt.

Datei anzeigen

@ -1,7 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

30
gradlew vendored
Datei anzeigen

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -80,11 +80,14 @@ do
esac esac
done done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -130,29 +133,22 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
if ! command -v java >/dev/null 2>&1 which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -197,10 +193,6 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in # shell script including quotes and variable substitutions, so put them in
@ -213,12 +205,6 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

15
gradlew.bat vendored
Datei anzeigen

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,8 +25,7 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -41,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -76,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL% if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
if %EXIT_CODE% equ 0 set EXIT_CODE=1 exit /b 1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

29
renovate.json Normale Datei
Datei anzeigen

@ -0,0 +1,29 @@
{
"extends": [
"config:base",
":disableDependencyDashboard"
],
"ignoreDeps": [
"guava",
"com.google.guava:guava",
"rhino-runtime",
"mockito-core",
"org.antlr",
"antlr4-runtime",
"fastutil",
"it.unimi.dsi:fastutil",
"auto-value-annotations",
"auto-value",
"com.google.code.gson:gson",
"net.fabricmc:fabric-loader",
"net.fabricmc.fabric-api:fabric-api",
"com.github.luben:zstd-jni"
],
"timezone": "Europe/Berlin",
"schedule": [
"on monday after 9am"
],
"labels": ["Renovate"],
"commitMessagePrefix": "build: ",
"rebaseWhen": "conflicted"
}

Datei anzeigen

@ -2,14 +2,15 @@ rootProject.name = "FastAsyncWorldEdit"
include("worldedit-libs") include("worldedit-libs")
listOf("legacy", "1_17_1", "1_18_2", "1_19", "1_19_3","1_19_4", "1_20").forEach { include("worldedit-bukkit:adapters:adapter-legacy")
include("worldedit-bukkit:adapters:adapter-$it") include("worldedit-bukkit:adapters:adapter-1_17_1")
} include("worldedit-bukkit:adapters:adapter-1_18")
listOf("bukkit", "core", "cli").forEach { listOf("bukkit", "core", "cli").forEach {
include("worldedit-libs:$it") include("worldedit-libs:$it")
include("worldedit-$it") include("worldedit-$it")
} }
// include("worldedit-mod")
include("worldedit-libs:core:ap") include("worldedit-libs:core:ap")
dependencyResolutionManagement { dependencyResolutionManagement {
@ -22,4 +23,5 @@ dependencyResolutionManagement {
} }
} }
enableFeaturePreview("VERSION_CATALOGS")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

Datei anzeigen

@ -1,9 +0,0 @@
build:
- "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew build"
- "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop"
artifacts:
"/binarys/FastAsyncWorldEdit-1.18.jar": "worldedit-bukkit/build/libs/FastAsyncWorldEdit-Bukkit-2.7.1-SNAPSHOT.jar"
release:
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=fastasyncworldedit -Dversion=1.18 -Dpackaging=jar -Dfile=/binarys/FastAsyncWorldEdit-1.18.jar -Durl=file:///var/www/html/maven/"

Datei anzeigen

@ -1,5 +1,3 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
applyPaperweightAdapterConfiguration() applyPaperweightAdapterConfiguration()
plugins { plugins {
@ -8,7 +6,10 @@ plugins {
repositories { repositories {
mavenCentral() mavenCentral()
gradlePluginPortal() maven {
name = "PaperMC"
url = uri("https://papermc.io/repo/repository/maven-public/")
}
} }
java { java {
@ -21,6 +22,6 @@ configurations.all {
dependencies { dependencies {
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.17.1-R0.1-20220414.034903-210") paperDevBundle("1.17.1-R0.1-20211219.175449-201")
compileOnly(libs.paperlib) compileOnly(libs.paperlib)
} }

Datei anzeigen

@ -28,6 +28,8 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
@ -54,7 +56,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
@ -85,7 +86,10 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.resources.RegistryReadOps;
import net.minecraft.resources.RegistryWriteOps;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@ -148,14 +152,13 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
@ -168,11 +171,11 @@ import static com.google.common.base.Preconditions.checkState;
public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> { public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> {
private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
private final Field worldsField; private final Field serverWorldsField;
private final Method getChunkFutureMainThreadMethod; private final Method getChunkFutureMethod;
private final Field mainThreadProcessorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -188,18 +191,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
throw new UnsupportedClassVersionError("Not 1.17.1!"); throw new UnsupportedClassVersionError("Not 1.17.1!");
} }
worldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField = CraftServer.class.getDeclaredField("worlds");
worldsField.setAccessible(true); serverWorldsField.setAccessible(true);
getChunkFutureMainThreadMethod = ServerChunkCache.class.getDeclaredMethod("getChunkFutureMainThread", getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod("getChunkFutureMainThread",
int.class, int.class, ChunkStatus.class, boolean.class int.class, int.class, ChunkStatus.class, boolean.class
); );
getChunkFutureMainThreadMethod.setAccessible(true); getChunkFutureMethod.setAccessible(true);
mainThreadProcessorField = ServerChunkCache.class.getDeclaredField( chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "h") Refraction.pickName("mainThreadProcessor", "h")
); );
mainThreadProcessorField.setAccessible(true); chunkProviderExecutorField.setAccessible(true);
new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).build(ForkJoinPool.commonPool()); new PaperweightDataConverters(CraftMagicNumbers.INSTANCE.getDataVersion(), this).build(ForkJoinPool.commonPool());
@ -218,7 +221,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
@ -432,12 +435,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, tag); readEntityIntoTag(mcEntity, tag);
//FAWE start - BinaryTag return new BaseEntity(com.sk89q.worldedit.world.entity.EntityTypes.get(id), (CompoundTag) toNative(tag));
return new BaseEntity(
com.sk89q.worldedit.world.entity.EntityTypes.get(id),
LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag))
);
//FAWE end
} }
@Nullable @Nullable
@ -486,34 +484,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() {
@Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(),
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList()));
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList()));
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" })
@Override @Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) { public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, Property<?>> properties = new TreeMap<>(); Map<String, Property<?>> properties = Maps.newTreeMap(String::compareTo);
Block block = getBlockFromType(blockType); Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList = StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList =
block.getStateDefinition(); block.getStateDefinition();
for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state); Property property;
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
property = new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
property = new DirectionalProperty(
state.getName(),
(List<Direction>) state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName()
.toUpperCase(Locale.ROOT)))
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
property = new EnumProperty(
state.getName(),
(List<String>) 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(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
}
properties.put(property.getName(), property); properties.put(property.getName(), property);
} }
return properties; return properties;
@ -616,7 +622,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen"); Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen");
LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env); ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env);
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData(); .getWorldData().overworldData();
@ -624,11 +630,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
long seed = options.getSeed().orElse(originalWorld.getSeed()); long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldGenSettings newOpts = options.getSeed().isPresent() WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) ? replaceSeed(originalWorld, seed, originalOpts)
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
levelProperties.settings.gameType(), levelProperties.settings.gameType(),
levelProperties.settings.hardcore(), levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(), levelProperties.settings.difficulty(),
@ -661,14 +667,65 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) worldsField.get(Bukkit.getServer()); Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
SafeFiles.tryHardToDeleteDir(tempDir); SafeFiles.tryHardToDeleteDir(tempDir);
} }
} }
// FAWE start - private -> public static
public static WorldGenSettings replaceSeed(ServerLevel originalWorld, long seed, WorldGenSettings originalOpts) {
// FAWE end
RegistryWriteOps<net.minecraft.nbt.Tag> nbtReadRegOps = RegistryWriteOps.create(
NbtOps.INSTANCE,
originalWorld.getServer().registryAccess()
);
RegistryReadOps<net.minecraft.nbt.Tag> nbtRegOps = RegistryReadOps.createAndLoad(
NbtOps.INSTANCE,
originalWorld.getServer().getResourceManager(),
originalWorld.getServer().registryAccess()
);
Codec<WorldGenSettings> dimCodec = WorldGenSettings.CODEC;
return dimCodec
.encodeStart(nbtReadRegOps, originalOpts)
.flatMap(tag ->
dimCodec.parse(
recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>())
)
)
.get()
.map(
l -> l,
error -> {
throw new IllegalStateException("Unable to map GeneratorOptions: " + error.message());
}
);
}
// FAWE start - private -> private static
@SuppressWarnings("unchecked")
private static Dynamic<net.minecraft.nbt.Tag> recursivelySetSeed(
// FAWE end
Dynamic<net.minecraft.nbt.Tag> dynamic,
long seed,
Set<Dynamic<net.minecraft.nbt.Tag>> seen
) {
if (!seen.add(dynamic)) {
return dynamic;
}
return dynamic.updateMapValues(pair -> {
if (pair.getFirst().asString("").equals("seed")) {
return pair.mapSecond(v -> v.createLong(seed));
}
if (pair.getSecond().getValue() instanceof net.minecraft.nbt.CompoundTag) {
return pair.mapSecond(v -> recursivelySetSeed((Dynamic<net.minecraft.nbt.Tag>) v, seed, seen));
}
return pair;
});
}
private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) {
ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome); ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome);
if (key == null) { if (key == null) {
@ -683,7 +740,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld); List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld);
BlockableEventLoop<Runnable> executor; BlockableEventLoop<Runnable> executor;
try { try {
executor = (BlockableEventLoop<Runnable>) mainThreadProcessorField.get(serverWorld.getChunkSource()); executor = (BlockableEventLoop<Runnable>) chunkProviderExecutorField.get(serverWorld.getChunkSource());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalStateException("Couldn't get executor for chunk loading.", e); throw new IllegalStateException("Couldn't get executor for chunk loading.", e);
} }
@ -741,9 +798,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
// Pre-gen all the chunks // Pre-gen all the chunks
for (BlockVector2 chunk : region.getChunks()) { for (BlockVector2 chunk : region.getChunks()) {
try { try {
//noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>) ((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMainThreadMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.getX(), chunk.getZ(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null)) .thenApply(either -> either.left().orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
@ -835,7 +893,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
return toNativeList((net.minecraft.nbt.ListTag) foreign); return toNativeList((net.minecraft.nbt.ListTag) foreign);
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
return ListBinaryTag.empty(); return ListBinaryTag.empty();
} }
} else if (foreign instanceof net.minecraft.nbt.LongTag) { } else if (foreign instanceof net.minecraft.nbt.LongTag) {
@ -860,7 +918,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @throws IllegalArgumentException on error * @throws IllegalArgumentException on error
*/ */
private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException {
ListBinaryTag.Builder<BinaryTag> values = ListBinaryTag.builder(); ListBinaryTag.Builder values = ListBinaryTag.builder();
for (net.minecraft.nbt.Tag tag : foreign) { for (net.minecraft.nbt.Tag tag : foreign) {
values.add(toNativeBinary(tag)); values.add(toNativeBinary(tag));
@ -900,8 +958,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value());
} else if (foreign instanceof LongArrayBinaryTag) { } else if (foreign instanceof LongArrayBinaryTag) {
return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value());
} else if (foreign instanceof ListBinaryTag foreignList) { } else if (foreign instanceof ListBinaryTag) {
net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag();
ListBinaryTag foreignList = (ListBinaryTag) foreign;
for (BinaryTag t : foreignList) { for (BinaryTag t : foreignList) {
tag.add(fromNativeBinary(t)); tag.add(fromNativeBinary(t));
} }
@ -953,7 +1012,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
WatchdogThread.tick(); WatchdogThread.tick();
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); logger.log(Level.WARNING, "Failed to tick watchdog", e);
} }
} }
@ -990,7 +1049,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) {
} }
@Override @Override

Datei anzeigen

@ -6,14 +6,13 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
@ -41,9 +40,6 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -86,6 +82,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState;
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
@ -103,7 +100,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -144,7 +140,6 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return parent; return parent;
} }
@SuppressWarnings("unchecked")
private synchronized boolean init() { private synchronized boolean init() {
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false; return false;
@ -163,9 +158,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
try { try {
for (Field field : BlockStateProperties.class.getDeclaredFields()) { for (Field field : BlockStateProperties.class.getDeclaredFields()) {
Object obj = field.get(null); Object obj = field.get(null);
if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property<?> state)) { if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property)) {
continue; continue;
} }
net.minecraft.world.level.block.state.properties.Property<?> state = (net.minecraft.world.level.block.state.properties.Property<?>) obj;
Property<?> property; Property<?> property;
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
property = new BooleanProperty( property = new BooleanProperty(
@ -278,8 +274,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// Read the NBT data // Read the NBT data
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
//TODO 1.18 recheck logic, I may skipped loading - NMF
net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); net.minecraft.nbt.CompoundTag tag = blockEntity.save(new net.minecraft.nbt.CompoundTag());
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((CompoundTag) toNative(tag));
} }
} }
@ -291,7 +288,6 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return SideEffectSet.defaults().getSideEffectsToApply(); return SideEffectSet.defaults().getSideEffectsToApply();
} }
@SuppressWarnings("rawtypes")
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk; CraftChunk craftChunk = (CraftChunk) chunk;
LevelChunk levelChunk = craftChunk.getHandle(); LevelChunk levelChunk = craftChunk.getHandle();
@ -312,7 +308,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; CompoundTag compoundTag = state instanceof BaseBlock ? state.getNbtData() : null;
if (compoundTag != null || existing instanceof TileEntityBlock) { if (compoundTag != null || existing instanceof TileEntityBlock) {
level.setBlock(blockPos, blockState, 0); level.setBlock(blockPos, blockState, 0);
// remove tile // remove tile
@ -321,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// though we do not do this on the Forge version // though we do not do this on the Forge version
BlockEntity blockEntity = level.getBlockEntity(blockPos); BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(compoundTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
@ -365,14 +361,14 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { Supplier<CompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", new StringTag(id));
return CompoundBinaryTag.from(tags); return new CompoundTag(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -429,7 +425,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", 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 blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
); );
return BlockTypesCache.ReservedIDs.AIR; return 0;
} }
} }
} }
@ -545,7 +541,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())), Registry.ITEM.get(ResourceLocation.tryParse(baseItemStack.getType().getId())),
baseItemStack.getAmount() baseItemStack.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNativeBinary(baseItemStack.getNbt()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData())));
return CraftItemStack.asCraftMirror(stack); return CraftItemStack.asCraftMirror(stack);
} }
@ -563,26 +559,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
); // bukkit skips the feature gen which does this offset normally, so we have to add it back ); // bukkit skips the feature gen which does this offset normally, so we have to add it back
} }
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
final BlockVector3 finalBlockVector = blockVector3;
// Sync to main thread to ensure no clashes occur
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try { boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType);
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
}
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
}
});
if (placed == null || placed.isEmpty()) {
return false; return false;
} } else {
for (CraftBlockState craftBlockState : placed.values()) { for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue; continue;
} }
@ -590,8 +576,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
); );
} }
serverLevel.capturedBlockStates.clear();
return true; return true;
} }
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {
@ -614,7 +603,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
return weStack; return weStack;
} }
@ -643,13 +632,22 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public int getInternalBiomeId(BiomeType biomeType) { public int getInternalBiomeId(BiomeType biomeType) {
final Registry<Biome> registry = MinecraftServer if (biomeType.getId().startsWith("minecraft:")) {
.getServer() Biome biomeBase = CraftBlock.biomeToBiomeBase(
.registryAccess() 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); .ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId());
Biome biome = registry.get(resourceLocation); ResourceLocation resourceLocation = biomeRegistry.keySet().stream()
return registry.getId(biome); .filter(resource -> resource.toString().equals(biomeType.getId()))
.findAny().orElse(null);
return biomeRegistry.getId(biomeRegistry.get(resourceLocation));
}
} }
@Override @Override
@ -659,17 +657,10 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
.registryAccess() .registryAccess()
.ownedRegistryOrThrow( .ownedRegistryOrThrow(
Registry.BIOME_REGISTRY); Registry.BIOME_REGISTRY);
List<ResourceLocation> keys = biomeRegistry.stream() return biomeRegistry.stream()
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); .map(biomeRegistry::getKey)
List<NamespacedKey> namespacedKeys = new ArrayList<>(); .map(CraftNamespacedKey::fromMinecraft)
for (ResourceLocation key : keys) { .collect(Collectors.toList());
try {
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
} catch (IllegalArgumentException e) {
LOGGER.error("Error converting biome key {}", key.toString(), e);
}
}
return namespacedKeys;
} }
@Override @Override
@ -701,9 +692,4 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
} }
@Override
public IBatchProcessor getTickingPostProcessor() {
return new PaperweightPostProcessor();
}
} }

Datei anzeigen

@ -246,7 +246,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
} }
} }
}; };
@ -262,7 +262,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
} }
} }
}; };
@ -275,11 +275,21 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
cachedChunksToSend.clear(); cachedChunksToSend.clear();
} }
private record CachedChange( 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, LevelChunk levelChunk,
BlockPos blockPos, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState net.minecraft.world.level.block.state.BlockState blockState
) { ) {
this.levelChunk = levelChunk;
this.blockPos = blockPos;
this.blockState = blockState;
}
} }

Datei anzeigen

@ -11,9 +11,9 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
@ -25,7 +25,6 @@ import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -58,14 +57,15 @@ import org.bukkit.World;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull; import javax.annotation.Nullable;
import java.util.AbstractSet; import java.util.AbstractSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -73,11 +73,9 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
@ -173,8 +171,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public void setHeightmapToGet(HeightMapType type, int[] data) { public void setHeightmapToGet(HeightMapType type, int[] data) {
// height + 1 to match server internal BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256);
bitArray.fromRaw(data); bitArray.fromRaw(data);
Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name());
Heightmap heightMap = getChunk().heightmaps.get(nativeType); Heightmap heightMap = getChunk().heightmaps.get(nativeType);
@ -328,9 +325,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
} }
for (CompoundTag tag : getEntities()) { for (List<Entity> entry : /*getChunk().getEntitySlices()*/ new List[0]) {
if (uuid.equals(tag.getUUID())) { if (entry != null) {
return tag; for (Entity ent : entry) {
if (uuid.equals(ent.getUUID())) {
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
}
}
} }
} }
return null; return null;
@ -338,15 +340,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public Set<CompoundTag> getEntities() { public Set<CompoundTag> getEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity>[] slices = /*getChunk().getEntitySlices()*/ new List[0];
if (entities.isEmpty()) { int size = 0;
for (List<Entity> slice : slices) {
if (slice != null) {
size += slice.size();
}
}
if (slices.length == 0) {
return Collections.emptySet(); return Collections.emptySet();
} }
int size = entities.size(); int finalSize = size;
return new AbstractSet<>() { return new AbstractSet<CompoundTag>() {
@Override @Override
public int size() { public int size() {
return size; return finalSize;
} }
@Override @Override
@ -356,27 +364,40 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public boolean contains(Object get) { public boolean contains(Object get) {
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof CompoundTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); CompoundTag getTag = (CompoundTag) get;
for (Entity entity : entities) { Map<String, Tag> value = getTag.getValue();
CompoundTag getParts = (CompoundTag) value.get("UUID");
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
for (List<Entity> slice : slices) {
if (slice != null) {
for (Entity entity : slice) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
return true; return true;
} }
} }
}
}
return false; return false;
} }
@Nonnull @NotNull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<CompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<CompoundTag> result = Iterables.transform(
Iterables.concat(slices),
new com.google.common.base.Function<Entity, CompoundTag>() {
@Nullable
@Override
public CompoundTag apply(@Nullable Entity input) {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
input.save(tag); return (CompoundTag) adapter.toNative(input.saveWithoutId(tag));
return (CompoundTag) adapter.toNative(tag); }
}).collect(Collectors.toList()); }
);
return result.iterator(); return result.iterator();
} }
}; };
@ -391,10 +412,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
@SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null;
try { try {
ServerLevel nmsWorld = serverLevel; ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
@ -415,7 +435,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { if (ordinal != 0) {
BlockEntity tile = entry.getValue(); BlockEntity tile = entry.getValue();
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
if (beacons == null) { if (beacons == null) {
@ -445,11 +465,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
bitMask |= 1 << layer; bitMask |= 1 << layer;
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
// this chunk GET when #updateGet is called. Future dords, please listen this time.
char[] tmp = set.load(layerNo); char[] tmp = set.load(layerNo);
char[] setArr = new char[tmp.length]; char[] setArr = new char[4096];
System.arraycopy(tmp, 0, setArr, 0, tmp.length); System.arraycopy(tmp, 0, setArr, 0, 4096);
// synchronise on internal section to avoid circular locking with a continuing edit if the chunk was // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was
// submitted to keep loaded internal chunks to queue target size. // submitted to keep loaded internal chunks to queue target size.
@ -463,14 +481,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
LevelChunkSection newSection; LevelChunkSection newSection;
LevelChunkSection existingSection = levelChunkSections[layer]; LevelChunkSection existingSection = levelChunkSections[layer];
// Don't attempt to tick section whilst we're editing
if (existingSection != null) {
PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
}
}
if (existingSection == null) { if (existingSection == null) {
newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter); newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter);
if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) { if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) {
@ -486,18 +496,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} }
PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0);
//ensure that the server doesn't try to tick the chunksection while we're editing it (again). //ensure that the server doesn't try to tick the chunksection while we're editing it.
PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
// Synchronize to prevent further acquisitions
synchronized (lock) { synchronized (lock) {
lock.acquire(); // Wait until we have the lock // lock.acquire();
lock.release();
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
if (this.getChunk() != nmsChunk) { if (this.getChunk() != nmsChunk) {
@ -612,31 +617,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
syncTasks[2] = () -> { syncTasks[2] = () -> {
Set<UUID> entitiesRemoved = new HashSet<>(); final List<Entity>[] entities = /*nmsChunk.e()*/ new List[0];
final List<Entity> entities = PaperweightPlatformAdapter.getEntities(nmsChunk);
for (Entity entity : entities) { for (final Collection<Entity> ents : entities) {
UUID uuid = entity.getUUID(); if (!ents.isEmpty()) {
if (entityRemoves.contains(uuid)) { final Iterator<Entity> iter = ents.iterator();
while (iter.hasNext()) {
final Entity entity = iter.next();
if (entityRemoves.contains(entity.getUUID())) {
if (createCopy) { if (createCopy) {
copy.storeEntity(entity); copy.storeEntity(entity);
} }
removeEntity(entity); iter.remove();
entitiesRemoved.add(uuid);
entityRemoves.remove(uuid);
}
}
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid);
if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
} }
} }
// Only save entities that were actually removed to history }
set.getEntityRemoves().clear();
set.getEntityRemoves().addAll(entitiesRemoved);
}; };
} }
@ -647,9 +644,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); for (final CompoundTag nativeTag : entities) {
while (iterator.hasNext()) {
final CompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final Map<String, Tag> entityTagMap = nativeTag.getValue();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final StringTag idTag = (StringTag) entityTagMap.get("Id");
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag posTag = (ListTag) entityTagMap.get("Pos");
@ -676,23 +671,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
if (!nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id,
nmsWorld.getWorld().getName(),
x,
y,
z
);
// Unsuccessful create should not be saved to history
iterator.remove();
}
} }
} }
} }
}; };
} }
// set tiles // set tiles
@ -776,7 +760,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
throw e; throw e;
} }
}; };
//noinspection unchecked - required at compile time
return (T) (Future) queueHandler.sync(chain); return (T) (Future) queueHandler.sync(chain);
} else { } else {
if (callback == null) { if (callback == null) {
@ -856,24 +839,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
* @return the given array to be filled with data, or a new array if null is given. * @return the given array to be filled with data, or a new array if null is given.
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public char[] update(int layer, char[] data, boolean aggressive) { public char[] update(int layer, char[] data, boolean aggressive) {
LevelChunkSection section = getSections(aggressive)[layer]; LevelChunkSection section = getSections(aggressive)[layer];
// Section is null, return empty array // Section is null, return empty array
if (section == null) { if (section == null) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
return data; return data;
} }
if (data != null && data.length != 4096) { if (data != null && data.length != 4096) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
} }
if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
} }
Semaphore lock = PaperweightPlatformAdapter.applyLock(section); DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) { synchronized (lock) {
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {
@ -896,7 +878,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {
char paletteVal = data[i]; char paletteVal = data[i];
char ordinal = adapter.ibdIDToOrdinal(paletteVal); char ordinal = adapter.ibdIDToOrdinal(paletteVal);
data[i] = ordinal; // Don't read "empty".
data[i] = ordinal == 0 ? 1 : ordinal;
} }
return data; return data;
} }
@ -915,10 +898,18 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
val = ordinal(palette.valueFor(i), adapter); val = ordinal(palette.valueFor(i), adapter);
paletteToOrdinal[i] = val; paletteToOrdinal[i] = val;
} }
// Don't read "empty".
if (val == 0) {
val = 1;
}
data[i] = val; data[i] = val;
} }
} else { } else {
char ordinal = ordinal(palette.valueFor(0), adapter); char ordinal = ordinal(palette.valueFor(0), adapter);
// Don't read "empty".
if (ordinal == 0) {
ordinal = 1;
}
Arrays.fill(data, ordinal); Arrays.fill(data, ordinal);
} }
} finally { } finally {
@ -938,7 +929,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) { private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) {
if (ibd == null) { if (ibd == null) {
return BlockTypesCache.ReservedIDs.AIR; return 1;
} else { } else {
return adapter.adaptToChar(ibd); return adapter.adaptToChar(ibd);
} }
@ -1020,7 +1011,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
@SuppressWarnings("unchecked")
public synchronized boolean trim(boolean aggressive) { public synchronized boolean trim(boolean aggressive) {
skyLight = new DataLayer[getSectionCount()]; skyLight = new DataLayer[getSectionCount()];
blockLight = new DataLayer[getSectionCount()]; blockLight = new DataLayer[getSectionCount()];

Datei anzeigen

@ -19,7 +19,6 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.ChunkBiomeContainer; import net.minecraft.world.level.chunk.ChunkBiomeContainer;
import net.minecraft.world.level.chunk.LevelChunk;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
@ -36,15 +35,13 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; private final ServerLevel serverLevel;
final LevelChunk levelChunk;
private ChunkBiomeContainer chunkBiomeContainer; private ChunkBiomeContainer chunkBiomeContainer;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(ServerLevel world) {
this.levelChunk = levelChunk; this.serverLevel = world;
this.serverLevel = levelChunk.level; this.minHeight = world.getMinBuildHeight();
this.minHeight = serverLevel.getMinBuildHeight(); this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][]; this.blocks = new char[getSectionCount()][];
} }
@ -70,12 +67,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return tiles.get(BlockVector3.at(x, y, z)); return tiles.get(BlockVector3.at(x, y, z));
} }
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag)));
entities.add((CompoundTag) adapter.toNative(compoundTag));
} }
@Override @Override
@ -86,7 +81,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public CompoundTag getEntity(UUID uuid) { public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) { for (CompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { 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 tag;
} }
} }

Datei anzeigen

@ -12,7 +12,7 @@ import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
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.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
@ -30,10 +30,7 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
import net.minecraft.util.Unit;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
@ -49,8 +46,6 @@ import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.gameevent.GameEventDispatcher; import net.minecraft.world.level.gameevent.GameEventDispatcher;
import net.minecraft.world.level.gameevent.GameEventListener; import net.minecraft.world.level.gameevent.GameEventListener;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk;
import sun.misc.Unsafe; import sun.misc.Unsafe;
@ -59,13 +54,12 @@ import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -77,9 +71,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldBitsPerEntry; public static final Field fieldBitsPerEntry;
private static final Field fieldTickingFluidContent; public static final Field fieldTickingFluidContent;
private static final Field fieldTickingBlockCount; public static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; public static final Field fieldNonEmptyBlockCount;
private static final Field fieldBiomes; private static final Field fieldBiomes;
@ -92,12 +86,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final long fieldLockOffset; private static final long fieldLockOffset;
private static final Field fieldGameEventDispatcherSections; private static final Field fieldGameEventDispatcherSections;
private static final MethodHandle methodremoveBlockEntityTicker; private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldRemove; private static final Field fieldRemove;
private static final Logger LOGGER = LogManagerCompat.getLogger();
static { static {
try { try {
fieldBits = PalettedContainer.class.getDeclaredField(Refraction.pickName("bits", "l")); fieldBits = PalettedContainer.class.getDeclaredField(Refraction.pickName("bits", "l"));
@ -128,15 +120,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) {
fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
} else {
// in paper, the used methods are synchronized properly
fieldLock = null;
fieldLockOffset = -1;
}
fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
"gameEventDispatcherSections", "x")); "gameEventDispatcherSections", "x"));
@ -148,7 +133,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
), BlockPos.class ), BlockPos.class
); );
removeBlockEntityTicker.setAccessible(true); removeBlockEntityTicker.setAccessible(true);
methodremoveBlockEntityTicker = MethodHandles.lookup().unreflect(removeBlockEntityTicker); methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true); fieldRemove.setAccessible(true);
@ -180,21 +165,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return false; return false;
} }
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> SEMAPHORE_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null));
static DelegateSemaphore applyLock(LevelChunkSection section) { static DelegateSemaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) { //todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
return SEMAPHORE_THREAD_LOCAL.get();
}
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
Semaphore currentLock = (Semaphore) unsafe.getObject(blocks, fieldLockOffset); Semaphore currentLock = (Semaphore) unsafe.getObject(blocks, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) { if (currentLock instanceof DelegateSemaphore) {
return delegateSemaphore; return (DelegateSemaphore) currentLock;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(blocks, fieldLockOffset, newLock); unsafe.putObject(blocks, fieldLockOffset, newLock);
@ -218,12 +197,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} else { } else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) { if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk; return nmsChunk;
} }
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) { if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk; return nmsChunk;
} }
// Avoid "async" methods from the main thread. // Avoid "async" methods from the main thread.
@ -232,21 +209,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try { try {
CraftChunk chunk; CraftChunk chunk = (CraftChunk) future.get();
try {
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
String world = serverLevel.getWorld().getName();
// We've already taken 10 seconds we can afford to wait a little here.
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
if (loaded) {
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
// Retry chunk load
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
} else {
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
}
}
return chunk.getHandle(); return chunk.getHandle();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -255,13 +218,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
} }
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket
net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource()
.addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try { try {
@ -271,7 +227,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
} }
@SuppressWarnings("unchecked")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) { if (chunkHolder == null) {
@ -315,20 +270,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
NMS conversion NMS conversion
*/ */
public static LevelChunkSection newChunkSection( public static LevelChunkSection newChunkSection(
final int layer, final int layer, final char[] blocks, boolean fastmode,
final char[] blocks,
boolean fastMode,
CachedBukkitAdapter adapter CachedBukkitAdapter adapter
) { ) {
return newChunkSection(layer, null, blocks, fastMode, adapter); return newChunkSection(layer, null, blocks, fastmode, adapter);
} }
public static LevelChunkSection newChunkSection( public static LevelChunkSection newChunkSection(
final int layer, final int layer, final Function<Integer, char[]> get, char[] set,
final Function<Integer, char[]> get, boolean fastmode, CachedBukkitAdapter adapter
char[] set,
boolean fastMode,
CachedBukkitAdapter adapter
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer); return newChunkSection(layer);
@ -338,22 +288,19 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try { try {
int num_palette; int[] num_palette_buffer = new int[1];
final short[] nonEmptyBlockCount = fastMode ? new short[1] : null; Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
int air;
if (get == null) { if (get == null) {
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, nonEmptyBlockCount); air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
set, ticking_blocks, fastmode, adapter
);
} else { } else {
num_palette = createPalette( air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
layer, num_palette_buffer, get, set, ticking_blocks, fastmode, adapter
blockToPalette,
paletteToBlock,
blocksCopy,
get,
set,
adapter,
nonEmptyBlockCount
); );
} }
int num_palette = num_palette_buffer[0];
// BlockStates // BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1); int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) { if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
@ -416,27 +363,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldStorage.set(dataPaletteBlocks, nmsBits); fieldStorage.set(dataPaletteBlocks, nmsBits);
fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer); fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
fieldBits.set(dataPaletteBlocks, bitsPerEntry); fieldBits.set(dataPaletteBlocks, bitsPerEntry);
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) { } catch (final IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (!fastMode) {
levelChunkSection.recalcBlockCounts();
} else {
try {
fieldNonEmptyBlockCount.set(levelChunkSection, nonEmptyBlockCount[0]);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return levelChunkSection; return levelChunkSection;
} catch (final Throwable e) { } catch (final Throwable e) {
throw e;
} finally {
Arrays.fill(blockToPalette, Integer.MAX_VALUE); Arrays.fill(blockToPalette, Integer.MAX_VALUE);
Arrays.fill(paletteToBlock, Integer.MAX_VALUE); throw e;
Arrays.fill(blockStates, 0);
Arrays.fill(blocksCopy, 0);
} }
} }
@ -444,9 +385,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(layer); return new LevelChunkSection(layer);
} }
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
fieldTickingFluidContent.setShort(section, (short) 0); IllegalAccessException {
fieldTickingBlockCount.setShort(section, (short) 0); fieldTickingFluidContent.setShort(section, (short) 0); // TODO FIXME
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
} }
public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) { public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) {
@ -469,7 +412,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT)); return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT));
} }
@SuppressWarnings("unchecked")
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try { try {
// Do the method ourselves to avoid trying to reflect generic method parameters // Do the method ourselves to avoid trying to reflect generic method parameters
@ -498,14 +440,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldRemove.set(beacon, true); fieldRemove.set(beacon, true);
} }
} }
methodremoveBlockEntityTicker.invoke(levelChunk, beacon.getBlockPos()); methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) { } catch (Throwable throwable) {
throwable.printStackTrace(); throwable.printStackTrace();
} }
} }
static List<Entity> getEntities(LevelChunk chunk) {
return chunk.level.entityManager.getEntities(chunk.getPos());
}
} }

Datei anzeigen

@ -1,175 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import javax.annotation.Nullable;
public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@SuppressWarnings("deprecation")
@Override
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
// The PostProcessor shouldn't be added, but just in case
if (!tickFluid) {
return;
}
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
layer:
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
char[] set = iChunkSet.loadIfPresent(layer);
if (set == null) {
// No edit means no need to process
continue;
}
char[] get = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean fromGet = false; // Used for liquids
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (get == null) {
get = getBlocks.load(layer);
}
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
// actually being set
if (get == null) {
continue layer;
}
fromGet = true;
ordinal = replacedOrdinal = get[i];
}
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
continue;
} else if (!fromGet) { // if fromGet, don't do the same again
if (get == null) {
get = getBlocks.load(layer);
}
replacedOrdinal = get[i];
}
boolean ticking = BlockTypesCache.ticking[ordinal];
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
boolean replacedWasLiquid = false;
BlockState replacedState = null;
if (!ticking) {
// If the block being replaced was not ticking, it cannot be a liquid
if (!replacedWasTicking) {
continue;
}
// If the block being replaced is not fluid, we do not need to worry
if (!(replacedWasLiquid =
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
continue;
}
}
BlockState state = BlockState.getFromOrdinal(ordinal);
boolean liquid = state.getMaterial().isLiquid();
int x = i & 15;
int y = (i >> 8) & 15;
int z = (i >> 4) & 15;
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
if (liquid || replacedWasLiquid) {
if (liquid) {
addFluid(getBlocks.serverLevel, state, position);
continue;
}
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
// being ticked anyway. We only need it to be "hit" once.
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
continue;
}
addFluid(getBlocks.serverLevel, replacedState, position);
}
}
}
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
if (set == null || get == null) {
return false;
}
char ordinal;
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
if (x > 0 && set[i - 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
return true;
}
}
if (x < 15 && set[i + 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
return true;
}
}
if (z > 0 && set[i - 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
return true;
}
}
if (z < 15 && set[i + 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
return true;
}
}
if (y > 0 && set[i - 256] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
return true;
}
}
if (y < 15 && set[i + 256] != reserved) {
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isFluid(char ordinal) {
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
}
@SuppressWarnings("deprecation")
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
Fluid type;
if (replacedState.getBlockType() == BlockTypes.LAVA) {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
} else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
}
serverLevel.getLiquidTicks().scheduleTick(
position,
type,
type.getTickDelay(serverLevel)
);
}
}

Datei anzeigen

@ -70,7 +70,6 @@ public class PaperweightStarlightRelighter implements Relighter {
private final ReentrantLock areaLock = new ReentrantLock(); private final ReentrantLock areaLock = new ReentrantLock();
private final NMSRelighter delegate; private final NMSRelighter delegate;
@SuppressWarnings("rawtypes")
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) { public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) {
this.serverLevel = serverLevel; this.serverLevel = serverLevel;
this.delegate = new NMSRelighter(queue); this.delegate = new NMSRelighter(queue);

Datei anzeigen

@ -16,7 +16,6 @@ public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override @Override
public @Nonnull public @Nonnull
@SuppressWarnings("rawtypes")
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) { Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName()); org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) { if (w == null) {

Datei anzeigen

@ -35,7 +35,6 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@Override @Override
@SuppressWarnings("unchecked")
public Map<String, Tag> getValue() { public Map<String, Tag> getValue() {
if (compoundTag == null) { if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
@ -67,8 +66,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public double asDouble(String key) { public double asDouble(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsDouble(); return ((NumericTag) tag).getAsDouble();
} }
return 0; return 0;
} }
@ -87,20 +86,20 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public int asInt(String key) { public int asInt(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsInt(); return ((NumericTag) tag).getAsInt();
} }
return 0; return 0;
} }
@SuppressWarnings("unchecked")
public List<Tag> getList(String key) { public List<Tag> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) { if (tag instanceof net.minecraft.nbt.ListTag) {
ArrayList<Tag> list = new ArrayList<>(); ArrayList<Tag> list = new ArrayList<>();
net.minecraft.nbt.ListTag nbtList = (net.minecraft.nbt.ListTag) tag;
for (net.minecraft.nbt.Tag elem : nbtList) { for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { if (elem instanceof net.minecraft.nbt.CompoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag)); list.add(new PaperweightLazyCompoundTag((net.minecraft.nbt.CompoundTag) elem));
} else { } else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
} }
@ -110,7 +109,6 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
return Collections.emptyList(); return Collections.emptyList();
} }
@SuppressWarnings("unchecked")
public ListTag getListTag(String key) { public ListTag getListTag(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag) { if (tag instanceof net.minecraft.nbt.ListTag) {
@ -139,8 +137,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public long asLong(String key) { public long asLong(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsLong(); return ((NumericTag) tag).getAsLong();
} }
return 0; return 0;
} }

Datei anzeigen

@ -11,6 +11,7 @@ import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.PaperweightAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightGetBlocks; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.PaperweightGetBlocks;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
@ -37,7 +38,6 @@ import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.biome.OverworldBiomeSource; import net.minecraft.world.level.biome.OverworldBiomeSource;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
@ -67,7 +67,6 @@ import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.BlockPopulator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -79,7 +78,6 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.OptionalLong;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -92,13 +90,13 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field worldsField; private static final Field serverWorldsField;
private static final Field paperConfigField; private static final Field worldPaperConfigField;
private static final Field generateFlatBedrockField; private static final Field flatBedrockField;
private static final Field generatorSettingFlatField; private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField; private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField; private static final Field delegateField;
private static final Field chunkSourceField; private static final Field chunkProviderField;
//list of chunk stati in correct order without FULL //list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>(); private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
@ -127,8 +125,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try { try {
worldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField = CraftServer.class.getDeclaredField("worlds");
worldsField.setAccessible(true); serverWorldsField.setAccessible(true);
Field tmpPaperConfigField; Field tmpPaperConfigField;
Field tmpFlatBedrockField; Field tmpFlatBedrockField;
@ -142,8 +140,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
tmpPaperConfigField = null; tmpPaperConfigField = null;
tmpFlatBedrockField = null; tmpFlatBedrockField = null;
} }
paperConfigField = tmpPaperConfigField; worldPaperConfigField = tmpPaperConfigField;
generateFlatBedrockField = tmpFlatBedrockField; flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "g")); "settings", "g"));
@ -155,8 +153,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true); delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C")); chunkProviderField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "C"));
chunkSourceField.setAccessible(true); chunkProviderField.setAccessible(true);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -189,9 +187,9 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
//flat bedrock? (only on paper) //flat bedrock? (only on paper)
if (paperConfigField != null) { if (worldPaperConfigField != null) {
try { try {
generateFlatBedrock = generateFlatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalServerWorld));
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
@ -212,18 +210,18 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment); ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); session = levelStorageSource.createAccess("worldeditregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
BiomeProvider biomeProvider = getBiomeProvider();
MinecraftServer server = originalServerWorld.getCraftServer().getServer(); MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldGenSettings originalOpts = originalWorldData.worldGenSettings(); PrimaryLevelData levelProperties = (PrimaryLevelData) server.getWorldData();
WorldGenSettings originalOpts = levelProperties.worldGenSettings();
WorldGenSettings newOpts = options.getSeed().isPresent() WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed)) ? PaperweightAdapter.replaceSeed(originalServerWorld, seed, originalOpts)
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
originalWorldData.settings.gameType(), originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(), originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(), originalWorldData.settings.difficulty(),
@ -250,7 +248,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
false, false,
environment, environment,
generator, generator,
biomeProvider originalBukkitWorld.getBiomeProvider()
) { ) {
private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse( private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(
options options
@ -272,8 +270,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
freshWorld.noSave = true; freshWorld.noSave = true;
removeWorldFromWorldsMap(); removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) { if (worldPaperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig); worldPaperConfigField.set(freshWorld, originalServerWorld.paperConfig);
} }
//generator //generator
@ -284,17 +282,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator) { } else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator) {
Supplier<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Supplier<NoiseGeneratorSettings>) generatorSettingBaseSupplierField Supplier<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Supplier<NoiseGeneratorSettings>) generatorSettingBaseSupplierField
.get(originalChunkProvider.getGenerator()); .get(originalChunkProvider.getGenerator());
BiomeSource biomeSource; BiomeSource biomeSource = originalChunkProvider.getGenerator().getBiomeSource();
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(options
.getBiomeType()
.getId())));
} else {
biomeSource = originalChunkProvider.getGenerator().getBiomeSource();
if (biomeSource instanceof OverworldBiomeSource) { if (biomeSource instanceof OverworldBiomeSource) {
biomeSource = fastOverworldBiomeSource(biomeSource); biomeSource = fastOverworldBiomeSource(biomeSource);
} }
}
chunkGenerator = new NoiseBasedChunkGenerator(biomeSource, seed, generatorSettingBaseSupplier); chunkGenerator = new NoiseBasedChunkGenerator(biomeSource, seed, generatorSettingBaseSupplier);
} else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator) { } else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator) {
chunkGenerator = (ChunkGenerator) delegateField.get(originalChunkProvider.getGenerator()); chunkGenerator = (ChunkGenerator) delegateField.get(originalChunkProvider.getGenerator());
@ -323,16 +314,12 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
) { ) {
// redirect to LevelChunks created in #createChunks // redirect to LevelChunks created in #createChunks
@Override @Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean flag) {
ChunkAccess chunkAccess = getChunkAt(x, z); return getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
} }
}; };
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); ReflectionUtils.unsafeSet(chunkProviderField, freshWorld, freshChunkProvider);
//let's start then //let's start then
structureManager = server.getStructureManager(); structureManager = server.getStructureManager();
threadedLevelLightEngine = freshChunkProvider.getLightEngine(); threadedLevelLightEngine = freshChunkProvider.getLightEngine();
@ -415,12 +402,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
//util //util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() { private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> { Fawe.instance().getQueueHandler().sync(() -> {
try { try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) worldsField.get(Bukkit.getServer()); Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -428,14 +414,17 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) { private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) { switch (env) {
case NETHER -> LevelStem.NETHER; case NETHER:
case THE_END -> LevelStem.END; return LevelStem.NETHER;
default -> LevelStem.OVERWORLD; case THE_END:
}; return LevelStem.END;
case NORMAL:
default:
return LevelStem.OVERWORLD;
}
} }
@SuppressWarnings({"unchecked", "rawtypes"})
private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception { private BiomeSource fastOverworldBiomeSource(BiomeSource biomeSource) throws Exception {
Field legacyBiomeInitLayerField = OverworldBiomeSource.class.getDeclaredField( Field legacyBiomeInitLayerField = OverworldBiomeSource.class.getDeclaredField(
Refraction.pickName("legacyBiomeInitLayer", "i")); Refraction.pickName("legacyBiomeInitLayer", "i"));
@ -599,7 +588,17 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
private record FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, PixelTransformer transformer) implements Area { private static class FastAreaLazy implements Area {
private final PixelTransformer transformer;
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a synchronized context
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
private final ConcurrentHashMap<Long, Integer> sharedMap;
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, PixelTransformer transformer) {
this.sharedMap = sharedMap;
this.transformer = transformer;
}
@Override @Override
public int get(int x, int z) { public int get(int x, int z) {

Datei anzeigen

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

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
@ -27,13 +27,18 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.PaperweightFaweAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
@ -50,7 +55,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
@ -81,8 +85,11 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.resources.RegistryReadOps;
import net.minecraft.resources.RegistryWriteOps;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@ -113,6 +120,7 @@ import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelStorageSource;
@ -123,19 +131,20 @@ import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -144,54 +153,43 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> { public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft.nbt.Tag> {
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
);
private final Field serverWorldsField; private final Field serverWorldsField;
private final Method getChunkFutureMethod; private final Method getChunkFutureMethod;
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); private final Watchdog watchdog;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
private final Watchdog watchdog;
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new));
public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException {
// A simple test // A simple test
CraftServer.class.cast(Bukkit.getServer()); CraftServer.class.cast(Bukkit.getServer());
int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion();
if (dataVersion != 2975) { if (dataVersion != 2860 && dataVersion != 2865) {
throw new UnsupportedClassVersionError("Not 1.18.2!"); throw new UnsupportedClassVersionError("Not 1.18 or 1.18.1!");
} }
serverWorldsField = CraftServer.class.getDeclaredField("worlds"); serverWorldsField = CraftServer.class.getDeclaredField("worlds");
@ -204,7 +202,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
getChunkFutureMethod.setAccessible(true); getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g") Refraction.pickName("mainThreadProcessor", "h")
); );
chunkProviderExecutorField.setAccessible(true); chunkProviderExecutorField.setAccessible(true);
@ -225,11 +223,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
@Override
public DataFixer getDataFixer() {
return PaperweightDataConverters.INSTANCE;
}
/** /**
* Read the given NBT data into the given tile entity. * Read the given NBT data into the given tile entity.
* *
@ -291,29 +294,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return Registry.ITEM.get(ResourceLocation.tryParse(itemType.getId())); return Registry.ITEM.get(ResourceLocation.tryParse(itemType.getId()));
} }
private static net.minecraft.core.Direction adapt(Direction face) {
switch (face) {
case NORTH:
return net.minecraft.core.Direction.NORTH;
case SOUTH:
return net.minecraft.core.Direction.SOUTH;
case WEST:
return net.minecraft.core.Direction.WEST;
case EAST:
return net.minecraft.core.Direction.EAST;
case DOWN:
return net.minecraft.core.Direction.DOWN;
case UP:
default:
return net.minecraft.core.Direction.UP;
}
}
@Override
public DataFixer getDataFixer() {
return PaperweightDataConverters.INSTANCE;
}
@Override @Override
public OptionalInt getInternalBlockStateId(BlockData data) { public OptionalInt getInternalBlockStateId(BlockData data) {
net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState();
@ -343,9 +323,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
final ServerLevel handle = craftWorld.getHandle(); final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final CraftBlockData blockData = chunk.getBlockState(blockPos).createCraftBlockData();
int internalId = Block.getId(blockData); BlockState state = BukkitAdapter.adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) { if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock(); org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
@ -387,6 +366,24 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
); );
} }
private static net.minecraft.core.Direction adapt(Direction face) {
switch (face) {
case NORTH:
return net.minecraft.core.Direction.NORTH;
case SOUTH:
return net.minecraft.core.Direction.SOUTH;
case WEST:
return net.minecraft.core.Direction.WEST;
case EAST:
return net.minecraft.core.Direction.EAST;
case DOWN:
return net.minecraft.core.Direction.DOWN;
case UP:
default:
return net.minecraft.core.Direction.UP;
}
}
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties( private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer, StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
@ -430,12 +427,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, tag); readEntityIntoTag(mcEntity, tag);
//FAWE start - CompoundBinaryTag return new BaseEntity(com.sk89q.worldedit.world.entity.EntityTypes.get(id), (CompoundTag) toNative(tag));
return new BaseEntity(
com.sk89q.worldedit.world.entity.EntityTypes.get(id),
LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag))
);
//FAWE end
} }
@Nullable @Nullable
@ -450,9 +442,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle()); Entity createdEntity = createEntityFromId(state.getType().getId(), craftWorld.getHandle());
if (createdEntity != null) { if (createdEntity != null) {
CompoundBinaryTag nativeTag = state.getNbt(); CompoundTag nativeTag = state.getNbtData();
if (nativeTag != null) { if (nativeTag != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(nativeTag);
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
@ -484,40 +476,47 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() {
@Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(),
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList()));
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList()));
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state.getClass().getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" })
@Override @Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) { public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, Property<?>> properties = new TreeMap<>(); Map<String, Property<?>> properties = Maps.newTreeMap(String::compareTo);
Block block = getBlockFromType(blockType); Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList = StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList =
block.getStateDefinition(); block.getStateDefinition();
for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state); Property property;
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
property = new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
property = new DirectionalProperty(
state.getName(),
(List<Direction>) state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName()
.toUpperCase(Locale.ROOT)))
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
property = new EnumProperty(
state.getName(),
(List<String>) 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(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
}
properties.put(property.getName(), property); properties.put(property.getName(), property);
} }
return properties; return properties;
} }
//FAWE start - CompoundBinaryTag > CompoundTag
@Override @Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) {
((CraftPlayer) player).getHandle().networkManager.send(ClientboundBlockEntityDataPacket.create( ((CraftPlayer) player).getHandle().networkManager.send(ClientboundBlockEntityDataPacket.create(
@ -528,7 +527,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
__ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData)
)); ));
} }
//FAWE end
@Override @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
@ -548,12 +546,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
//FAWE start - CBT > CT weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag())));
//FAWE end
return weStack; return weStack;
} }
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new));
@Override @Override
public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) {
CraftWorld craftWorld = (CraftWorld) world; CraftWorld craftWorld = (CraftWorld) world;
@ -621,7 +620,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen"); Path tempDir = Files.createTempDirectory("FastAsyncWorldEditWorldGen");
LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env); ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env);
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData(); .getWorldData().overworldData();
@ -629,11 +628,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
long seed = options.getSeed().orElse(originalWorld.getSeed()); long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldGenSettings newOpts = options.getSeed().isPresent() WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(levelProperties.isHardcore(), OptionalLong.of(seed)) ? replaceSeed(originalWorld, seed, originalOpts)
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
levelProperties.settings.gameType(), levelProperties.settings.gameType(),
levelProperties.settings.hardcore(), levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(), levelProperties.settings.difficulty(),
@ -648,7 +647,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
originalWorld.getServer().executor, originalWorld.getServer().executor,
session, newWorldData, session, newWorldData,
originalWorld.dimension(), originalWorld.dimension(),
originalWorld.dimensionTypeRegistration(), originalWorld.dimensionType(),
new NoOpWorldLoadListener(), new NoOpWorldLoadListener(),
newOpts.dimensions().get(worldDimKey).generator(), newOpts.dimensions().get(worldDimKey).generator(),
originalWorld.isDebug(), originalWorld.isDebug(),
@ -667,13 +666,64 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
@SuppressWarnings("unchecked") @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>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
SafeFiles.tryHardToDeleteDir(tempDir); SafeFiles.tryHardToDeleteDir(tempDir);
} }
} }
// FAWE start - private -> public static
public static WorldGenSettings replaceSeed(ServerLevel originalWorld, long seed, WorldGenSettings originalOpts) {
// FAWE end
RegistryWriteOps<net.minecraft.nbt.Tag> nbtReadRegOps = RegistryWriteOps.create(
NbtOps.INSTANCE,
originalWorld.getServer().registryAccess()
);
RegistryReadOps<net.minecraft.nbt.Tag> nbtRegOps = RegistryReadOps.createAndLoad(
NbtOps.INSTANCE,
originalWorld.getServer().getResourceManager(),
originalWorld.getServer().registryAccess()
);
Codec<WorldGenSettings> dimCodec = WorldGenSettings.CODEC;
return dimCodec
.encodeStart(nbtReadRegOps, originalOpts)
.flatMap(tag ->
dimCodec.parse(
recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>())
)
)
.get()
.map(
l -> l,
error -> {
throw new IllegalStateException("Unable to map GeneratorOptions: " + error.message());
}
);
}
// FAWE start - private -> private static
@SuppressWarnings("unchecked")
private static Dynamic<net.minecraft.nbt.Tag> recursivelySetSeed(
// FAWE end
Dynamic<net.minecraft.nbt.Tag> dynamic,
long seed,
Set<Dynamic<net.minecraft.nbt.Tag>> seen
) {
if (!seen.add(dynamic)) {
return dynamic;
}
return dynamic.updateMapValues(pair -> {
if (pair.getFirst().asString("").equals("seed")) {
return pair.mapSecond(v -> v.createLong(seed));
}
if (pair.getSecond().getValue() instanceof net.minecraft.nbt.CompoundTag) {
return pair.mapSecond(v -> recursivelySetSeed((Dynamic<net.minecraft.nbt.Tag>) v, seed, seen));
}
return pair;
});
}
private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) {
ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome); ResourceLocation key = serverWorld.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(origBiome);
if (key == null) { if (key == null) {
@ -713,8 +763,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()); BlockPos pos = new BlockPos(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ());
ChunkAccess chunk = chunks.get(new ChunkPos(pos)); ChunkAccess chunk = chunks.get(new ChunkPos(pos));
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(pos);
int internalId = Block.getId(blockData); BlockStateHolder<?> state = ((PaperweightFaweAdapter) WorldEditPlugin
BlockStateHolder<?> state = BlockStateIdAccess.getBlockStateById(internalId); .getInstance()
.getBukkitImplAdapter()).adapt(blockData);
Objects.requireNonNull(state); Objects.requireNonNull(state);
BlockEntity blockEntity = chunk.getBlockEntity(pos); BlockEntity blockEntity = chunk.getBlockEntity(pos);
if (blockEntity != null) { if (blockEntity != null) {
@ -725,7 +776,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
extent.setBlock(vec, state.toBaseBlock()); extent.setBlock(vec, state.toBaseBlock());
if (options.shouldRegenBiomes()) { if (options.shouldRegenBiomes()) {
Biome origBiome = chunk.getNoiseBiome(vec.getX(), vec.getY(), vec.getZ()).value(); PalettedContainer<Biome> biomeIndex = chunk.getSection(chunk.getSectionIndex(vec.getBlockY()))
.getBiomes();
Biome origBiome = biomeIndex.get(vec.getBlockX(), vec.getBlockY(), vec.getBlockZ());
BiomeType adaptedBiome = adapt(serverWorld, origBiome); BiomeType adaptedBiome = adapt(serverWorld, origBiome);
if (adaptedBiome != null) { if (adaptedBiome != null) {
extent.setBiome(vec, adaptedBiome); extent.setBiome(vec, adaptedBiome);
@ -766,6 +819,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
);
@Override @Override
public Set<SideEffect> getSupportedSideEffects() { public Set<SideEffect> getSupportedSideEffects() {
return SUPPORTED_SIDE_EFFECTS; return SUPPORTED_SIDE_EFFECTS;
@ -827,7 +889,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
return toNativeList((net.minecraft.nbt.ListTag) foreign); return toNativeList((net.minecraft.nbt.ListTag) foreign);
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e);
return ListBinaryTag.empty(); return ListBinaryTag.empty();
} }
} else if (foreign instanceof net.minecraft.nbt.LongTag) { } else if (foreign instanceof net.minecraft.nbt.LongTag) {
@ -852,7 +914,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* @throws IllegalArgumentException on error * @throws IllegalArgumentException on error
*/ */
private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException {
ListBinaryTag.Builder<BinaryTag> values = ListBinaryTag.builder(); ListBinaryTag.Builder values = ListBinaryTag.builder();
for (net.minecraft.nbt.Tag tag : foreign) { for (net.minecraft.nbt.Tag tag : foreign) {
values.add(toNativeBinary(tag)); values.add(toNativeBinary(tag));
@ -892,8 +954,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value());
} else if (foreign instanceof LongArrayBinaryTag) { } else if (foreign instanceof LongArrayBinaryTag) {
return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value());
} else if (foreign instanceof ListBinaryTag foreignList) { } else if (foreign instanceof ListBinaryTag) {
net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag();
ListBinaryTag foreignList = (ListBinaryTag) foreign;
for (BinaryTag t : foreignList) { for (BinaryTag t : foreignList) {
tag.add(fromNativeBinary(t)); tag.add(fromNativeBinary(t));
} }
@ -922,6 +985,35 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
watchdog.tick(); watchdog.tick();
} }
private class SpigotWatchdog implements Watchdog {
private final Field instanceField;
private final Field lastTickField;
SpigotWatchdog() throws NoSuchFieldException {
Field instanceField = WatchdogThread.class.getDeclaredField("instance");
instanceField.setAccessible(true);
this.instanceField = instanceField;
Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick");
lastTickField.setAccessible(true);
this.lastTickField = lastTickField;
}
@Override
public void tick() {
try {
WatchdogThread instance = (WatchdogThread) this.instanceField.get(null);
if ((long) lastTickField.get(instance) != 0) {
WatchdogThread.tick();
}
} catch (IllegalAccessException e) {
logger.log(Level.WARNING, "Failed to tick watchdog", e);
}
}
}
private static class MojangWatchdog implements Watchdog { private static class MojangWatchdog implements Watchdog {
private final DedicatedServer server; private final DedicatedServer server;
@ -953,7 +1045,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) {
} }
@Override @Override
@ -970,33 +1062,4 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private class SpigotWatchdog implements Watchdog {
private final Field instanceField;
private final Field lastTickField;
SpigotWatchdog() throws NoSuchFieldException {
Field instanceField = WatchdogThread.class.getDeclaredField("instance");
instanceField.setAccessible(true);
this.instanceField = instanceField;
Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick");
lastTickField.setAccessible(true);
this.lastTickField = lastTickField;
}
@Override
public void tick() {
try {
WatchdogThread instance = (WatchdogThread) this.instanceField.get(null);
if ((long) lastTickField.get(instance) != 0) {
WatchdogThread.tick();
}
} catch (IllegalAccessException e) {
LOGGER.log(Level.WARNING, "Failed to tick watchdog", e);
}
}
}
} }

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.ChatType;

Datei anzeigen

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -31,13 +31,13 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements public class PaperweightWorldNativeAccess implements
WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
@ -201,11 +201,9 @@ public class PaperweightWorldNativeAccess implements
getWorld().onBlockStateChange(pos, oldState, newState); getWorld().onBlockStateChange(pos, oldState, newState);
} }
//FAWE start
@Override @Override
public void flush() { public void flush() {
} }
//FAWE end
} }

Datei anzeigen

@ -1,10 +1,10 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.util.ReflectionUtil; import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
@ -15,7 +15,7 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material; import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
public class PaperweightBlockMaterial implements BlockMaterial { public class PaperweightBlockMaterial implements BlockMaterial {
@ -26,6 +26,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
private final int opacity; private final int opacity;
//TODO 1.18 be a CompoundBinaryTag ?
private final CompoundTag tile; private final CompoundTag tile;
public PaperweightBlockMaterial(Block block) { public PaperweightBlockMaterial(Block block) {
@ -39,7 +40,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
this.craftBlockData = CraftBlockData.fromData(blockState); this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial(); this.craftMaterial = craftBlockData.getMaterial();
BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName( BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, Refraction.pickName(
"properties", "aO")); "properties", "aP"));
this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo,
Refraction.pickName("canOcclude", "n") Refraction.pickName("canOcclude", "n")
); );

Datei anzeigen

@ -1,19 +1,19 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import ca.spottedleaf.starlight.common.light.StarLightEngine;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter; import com.fastasyncworldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity; import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
@ -21,9 +21,9 @@ import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R2.PaperweightAdapter; import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_18_R1.PaperweightAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen.PaperweightRegen; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
@ -41,9 +41,6 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -55,7 +52,6 @@ import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry; import net.minecraft.core.WritableRegistry;
@ -84,15 +80,16 @@ import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.TreeType;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlockState;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey; import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -104,7 +101,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -279,7 +275,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId();
return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); return state.toBaseBlock((CompoundTag) toNative(tag));
} }
} }
@ -291,6 +287,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return SideEffectSet.defaults().getSideEffectsToApply(); return SideEffectSet.defaults().getSideEffectsToApply();
} }
//TODO 1.18 address raw access of BlockStateHolder
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk; CraftChunk craftChunk = (CraftChunk) chunk;
LevelChunk levelChunk = craftChunk.getHandle(); LevelChunk levelChunk = craftChunk.getHandle();
@ -311,7 +308,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity levelChunk.removeBlockEntity(blockPos); // Force delete the old tile entity
CompoundBinaryTag compoundTag = state instanceof BaseBlock ? state.getNbt() : null; CompoundTag compoundTag = state instanceof BaseBlock ? state.getNbtData() : null;
if (compoundTag != null || existing instanceof TileEntityBlock) { if (compoundTag != null || existing instanceof TileEntityBlock) {
level.setBlock(blockPos, blockState, 0); level.setBlock(blockPos, blockState, 0);
// remove tile // remove tile
@ -320,7 +317,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
// though we do not do this on the Forge version // though we do not do this on the Forge version
BlockEntity blockEntity = level.getBlockEntity(blockPos); BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity != null) { if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(compoundTag); net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNative(compoundTag);
tag.put("x", IntTag.valueOf(x)); tag.put("x", IntTag.valueOf(x));
tag.put("y", IntTag.valueOf(y)); tag.put("y", IntTag.valueOf(y));
tag.put("z", IntTag.valueOf(z)); tag.put("z", IntTag.valueOf(z));
@ -358,14 +355,15 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
if (id != null) { if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundBinaryTag> saveTag = () -> { //TODO 1.18 be a CBT ?
Supplier<CompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag); readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work //add Id for AbstractChangeSet to work
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag); final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", StringBinaryTag.of(id)); tags.put("Id", new StringTag(id));
return CompoundBinaryTag.from(tags); return new CompoundTag(tags);
}; };
return new LazyBaseEntity(type, saveTag); return new LazyBaseEntity(type, saveTag);
} else { } else {
@ -422,7 +420,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", 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 blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
); );
return BlockTypesCache.ReservedIDs.AIR; return 0;
} }
} }
} }
@ -492,6 +490,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
ServerLevel nmsWorld = ((CraftWorld) world).getHandle(); ServerLevel nmsWorld = ((CraftWorld) world).getHandle();
ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && map.wasAccessibleSinceLastSave()) { if (map != null && map.wasAccessibleSinceLastSave()) {
boolean flag = false;
// PlayerChunk.d players = map.players; // PlayerChunk.d players = map.players;
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag) Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
*/ Stream.empty(); */ Stream.empty();
@ -555,26 +554,16 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
); // bukkit skips the feature gen which does this offset normally, so we have to add it back ); // bukkit skips the feature gen which does this offset normally, so we have to add it back
} }
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
final BlockVector3 finalBlockVector = blockVector3;
// Sync to main thread to ensure no clashes occur
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
try { boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType);
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
}
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
}
});
if (placed == null || placed.isEmpty()) {
return false; return false;
} } else {
for (CraftBlockState craftBlockState : placed.values()) { for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue; continue;
} }
@ -582,8 +571,11 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
); );
} }
serverLevel.capturedBlockStates.clear();
return true; return true;
} }
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {
@ -606,7 +598,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
return weStack; return weStack;
} }
@ -615,17 +607,12 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
return parent.toNative(foreign); return parent.toNative(foreign);
} }
@Override
public BinaryTag toNativeBinary(final net.minecraft.nbt.Tag foreign) {
return parent.toNativeBinary(foreign);
}
@Override @Override
public net.minecraft.nbt.Tag fromNative(Tag foreign) { public net.minecraft.nbt.Tag fromNative(Tag foreign) {
if (foreign instanceof PaperweightLazyCompoundTag) { if (foreign instanceof PaperweightLazyCompoundTag) {
return ((PaperweightLazyCompoundTag) foreign).get(); return ((PaperweightLazyCompoundTag) foreign).get();
} }
return (net.minecraft.nbt.Tag) parent.fromNative(foreign); return parent.fromNative(foreign);
} }
@Override @Override
@ -640,42 +627,50 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
@Override @Override
public int getInternalBiomeId(BiomeType biomeType) { public int getInternalBiomeId(BiomeType biomeType) {
final Registry<Biome> registry = MinecraftServer if (biomeType.getId().startsWith("minecraft:")) {
.getServer() Biome biomeBase = CraftBlock.biomeToBiomeBase(
.registryAccess() 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); .ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.getId());
Biome biome = registry.get(resourceLocation); ResourceLocation resourceLocation = biomeRegistry.keySet().stream()
return registry.getId(biome); .filter(resource -> resource.toString().equals(biomeType.getId()))
.findAny().orElse(null);
return biomeRegistry.getId(biomeRegistry.get(resourceLocation));
}
} }
@Override @Override
public Iterable<NamespacedKey> getRegisteredBiomes() { public Iterable<NamespacedKey> getRegisteredBiomes() {
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer()) WritableRegistry<Biome> biomeRegistry = ((CraftServer) Bukkit.getServer())
.getServer() .getServer()
.registryAccess() .registryAccess()
.ownedRegistryOrThrow( .ownedRegistryOrThrow(
Registry.BIOME_REGISTRY); Registry.BIOME_REGISTRY);
List<ResourceLocation> keys = biomeRegistry.stream() return biomeRegistry.stream()
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList(); .map(biomeRegistry::getKey)
List<NamespacedKey> namespacedKeys = new ArrayList<>(); .map(CraftNamespacedKey::fromMinecraft)
for (ResourceLocation key : keys) { .collect(Collectors.toList());
try {
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
} catch (IllegalArgumentException e) {
LOGGER.error("Error converting biome key {}", key.toString(), e);
}
}
return namespacedKeys;
} }
@Override @Override
public RelighterFactory getRelighterFactory() { public RelighterFactory getRelighterFactory() {
if (PaperLib.isPaper()) { try {
Class.forName("ca.spottedleaf.starlight.common.light.StarLightEngine");
if (PaperweightStarlightRelighter.isUsable()) {
return new PaperweightStarlightRelighterFactory(); return new PaperweightStarlightRelighterFactory();
} else {
return new NMSRelighterFactory();
} }
} catch (ThreadDeath td) {
throw td;
} catch (Throwable ignored) {
}
return new NMSRelighterFactory();
} }
@Override @Override
@ -692,9 +687,4 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
} }
} }
@Override
public IBatchProcessor getTickingPostProcessor() {
return new PaperweightPostProcessor();
}
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.math.IntPair;
@ -21,8 +21,8 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -246,7 +246,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
return; return;
} }
for (IntPair chunk : toSend) { for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
} }
} }
}; };
@ -262,7 +262,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
)); ));
for (IntPair chunk : cachedChunksToSend) { for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x(), chunk.z(), false); PaperweightPlatformAdapter.sendChunk(getLevel().getWorld().getHandle(), chunk.x, chunk.z, false);
} }
} }
}; };
@ -275,11 +275,21 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
cachedChunksToSend.clear(); cachedChunksToSend.clear();
} }
private record CachedChange( 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, LevelChunk levelChunk,
BlockPos blockPos, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState net.minecraft.world.level.block.state.BlockState blockState
) { ) {
this.levelChunk = levelChunk;
this.blockPos = blockPos;
this.blockState = blockState;
}
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler; import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.collection.AdaptedMap; import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -21,21 +20,18 @@ import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; import io.papermc.paper.event.block.BeaconDeactivatedEvent;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.nbt.IntTag; import net.minecraft.nbt.IntTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
@ -44,6 +40,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@ -58,18 +55,17 @@ import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.AbstractSet; import java.util.AbstractSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -77,7 +73,6 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
@ -103,7 +98,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private final int minSectionPosition; private final int minSectionPosition;
private final int maxSectionPosition; private final int maxSectionPosition;
private final Registry<Biome> biomeRegistry; private final Registry<Biome> biomeRegistry;
private final IdMap<Holder<Biome>> biomeHolderIdMap;
private LevelChunkSection[] sections; private LevelChunkSection[] sections;
private LevelChunk levelChunk; private LevelChunk levelChunk;
private DataLayer[] blockLight; private DataLayer[] blockLight;
@ -129,7 +123,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.skyLight = new DataLayer[getSectionCount()]; this.skyLight = new DataLayer[getSectionCount()];
this.blockLight = new DataLayer[getSectionCount()]; this.blockLight = new DataLayer[getSectionCount()];
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
} }
public int getChunkX() { public int getChunkX() {
@ -181,8 +174,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public void setHeightmapToGet(HeightMapType type, int[] data) { public void setHeightmapToGet(HeightMapType type, int[] data) {
// height + 1 to match server internal BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256);
bitArray.fromRaw(data); bitArray.fromRaw(data);
Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name());
Heightmap heightMap = getChunk().heightmaps.get(nativeType); Heightmap heightMap = getChunk().heightmaps.get(nativeType);
@ -202,7 +194,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()];
Holder<Biome> biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); Biome biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2);
return PaperweightPlatformAdapter.adapt(biomes, serverLevel); return PaperweightPlatformAdapter.adapt(biomes, serverLevel);
} }
@ -236,6 +228,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
//TODO 1.18 be CBT?
public CompoundTag getTile(int x, int y, int z) { public CompoundTag getTile(int x, int y, int z) {
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
chunkX << 4), y, (z & 15) + ( chunkX << 4), y, (z & 15) + (
@ -320,11 +313,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
Entity entity = serverLevel.getEntity(uuid); Entity entity = serverLevel.getEntity(uuid);
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
//TODO 1.18 CBT & #getNbt?
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
} }
for (CompoundTag tag : getEntities()) { for (List<Entity> entry : /*getChunk().getEntitySlices()*/ new List[0]) {
if (uuid.equals(tag.getUUID())) { if (entry != null) {
return tag; for (Entity ent : entry) {
if (uuid.equals(ent.getUUID())) {
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
}
}
} }
} }
return null; return null;
@ -332,15 +331,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public Set<CompoundTag> getEntities() { public Set<CompoundTag> getEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk()); List<Entity>[] slices = /*getChunk().getEntitySlices()*/ new List[0];
if (entities.isEmpty()) { int size = 0;
for (List<Entity> slice : slices) {
if (slice != null) {
size += slice.size();
}
}
if (slices.length == 0) {
return Collections.emptySet(); return Collections.emptySet();
} }
int size = entities.size(); int finalSize = size;
return new AbstractSet<>() { return new AbstractSet<CompoundTag>() {
@Override @Override
public int size() { public int size() {
return size; return finalSize;
} }
@Override @Override
@ -353,23 +358,28 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (!(get instanceof CompoundTag getTag)) { if (!(get instanceof CompoundTag getTag)) {
return false; return false;
} }
UUID getUUID = getTag.getUUID(); Map<String, Tag> value = getTag.getValue();
for (Entity entity : entities) { CompoundTag getParts = (CompoundTag) value.get("UUID");
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
for (List<Entity> slice : slices) {
if (slice != null) {
for (Entity entity : slice) {
UUID uuid = entity.getUUID(); UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) { if (uuid.equals(getUUID)) {
return true; return true;
} }
} }
}
}
return false; return false;
} }
@Nonnull @NotNull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<CompoundTag> iterator() {
Iterable<CompoundTag> result = entities.stream().map(input -> { Iterable<CompoundTag> result = StreamSupport.stream(Iterables.concat(slices).spliterator(), false).map(input -> {
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
input.save(tag); return (CompoundTag) adapter.toNative(input.saveWithoutId(tag));
return (CompoundTag) adapter.toNative(tag);
}).collect(Collectors.toList()); }).collect(Collectors.toList());
return result.iterator(); return result.iterator();
} }
@ -385,13 +395,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
@SuppressWarnings("rawtypes")
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) { public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false; forceLoadSections = false;
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null;
try { try {
ServerLevel nmsWorld = serverLevel; ServerLevel nmsWorld = serverLevel;
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE;
// Remove existing tiles. Create a copy so that we can remove blocks // Remove existing tiles. Create a copy so that we can remove blocks
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
@ -408,7 +418,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { if (ordinal != 0) {
BlockEntity tile = entry.getValue(); BlockEntity tile = entry.getValue();
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
if (beacons == null) { if (beacons == null) {
@ -452,23 +462,19 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( PalettedContainer<Biome> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
biomes[setSectionIndex], biomes[setSectionIndex],
biomeHolderIdMap biomeRegistry
); );
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
new char[4096], new char[4096],
fastmode,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, getSectionIndex)) {
levelChunkSections,
null,
newSection,
getSectionIndex
)) {
updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex);
continue; continue;
} else { } else {
@ -481,7 +487,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
PalettedContainer<Holder<Biome>> biomeData = existingSection.getBiomes(); PalettedContainer<Biome> biomeData = existingSection.getBiomes();
setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData);
} }
} }
@ -491,11 +497,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
bitMask |= 1 << getSectionIndex; bitMask |= 1 << getSectionIndex;
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
// this chunk GET when #updateGet is called. Future dords, please listen this time.
char[] tmp = set.load(layerNo); char[] tmp = set.load(layerNo);
char[] setArr = new char[tmp.length]; char[] setArr = new char[4096];
System.arraycopy(tmp, 0, setArr, 0, tmp.length); System.arraycopy(tmp, 0, setArr, 0, 4096);
// synchronise on internal section to avoid circular locking with a continuing edit if the chunk was // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was
// submitted to keep loaded internal chunks to queue target size. // submitted to keep loaded internal chunks to queue target size.
@ -503,13 +507,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
LevelChunkSection newSection; LevelChunkSection newSection;
LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
// Don't attempt to tick section whilst we're editing
if (existingSection != null) {
PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
}
}
if (createCopy) { if (createCopy) {
char[] tmpLoad = loadPrivately(layerNo); char[] tmpLoad = loadPrivately(layerNo);
@ -522,29 +519,21 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Biome> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeRegistry,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeRegistry.getOrThrow(Biomes.PLAINS),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES,
null null
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeRegistry);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
layerNo, layerNo,
setArr, setArr,
fastmode,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData
); );
if (PaperweightPlatformAdapter.setSectionAtomic( if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, getSectionIndex)) {
levelChunkSections,
null,
newSection,
getSectionIndex
)) {
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
continue; continue;
} else { } else {
@ -557,18 +546,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} }
PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0);
//ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) //ensure that the server doesn't try to tick the chunksection while we're editing it.
PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) {
existingSection.tickingList.clear();
}
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
// Synchronize to prevent further acquisitions
synchronized (lock) { synchronized (lock) {
lock.acquire(); // Wait until we have the lock // lock.acquire();
lock.release();
try { try {
sectionLock.writeLock().lock(); sectionLock.writeLock().lock();
if (this.getChunk() != nmsChunk) { if (this.getChunk() != nmsChunk) {
@ -578,10 +562,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} else if (existingSection != getSections(false)[getSectionIndex]) { } else if (existingSection != getSections(false)[getSectionIndex]) {
this.sections[getSectionIndex] = existingSection; this.sections[getSectionIndex] = existingSection;
this.reset(); this.reset();
} else if (!Arrays.equals( } else if (!Arrays.equals(update(getSectionIndex, new char[4096], true), loadPrivately(layerNo))) {
update(getSectionIndex, new char[4096], true),
loadPrivately(layerNo)
)) {
this.reset(layerNo); this.reset(layerNo);
/*} else if (lock.isModified()) { /*} else if (lock.isModified()) {
this.reset(layerNo);*/ this.reset(layerNo);*/
@ -590,7 +571,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
sectionLock.writeLock().unlock(); sectionLock.writeLock().unlock();
} }
PalettedContainer<Holder<Biome>> biomeData = existingSection.getBiomes(); PalettedContainer<Biome> biomeData = existingSection.getBiomes();
if (biomes != null && biomes[setSectionIndex] != null) { if (biomes != null && biomes[setSectionIndex] != null) {
setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData); setBiomesToPalettedContainer(biomes[setSectionIndex], biomeData);
@ -601,6 +582,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
layerNo, layerNo,
this::loadPrivately, this::loadPrivately,
setArr, setArr,
fastmode,
adapter, adapter,
biomeRegistry, biomeRegistry,
biomeData biomeData
@ -663,31 +645,23 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
syncTasks[2] = () -> { syncTasks[2] = () -> {
Set<UUID> entitiesRemoved = new HashSet<>(); final List<Entity>[] entities = /*nmsChunk.e()*/ new List[0];
final List<Entity> entities = PaperweightPlatformAdapter.getEntities(nmsChunk);
for (Entity entity : entities) { for (final Collection<Entity> ents : entities) {
UUID uuid = entity.getUUID(); if (!ents.isEmpty()) {
if (entityRemoves.contains(uuid)) { final Iterator<Entity> iter = ents.iterator();
while (iter.hasNext()) {
final Entity entity = iter.next();
if (entityRemoves.contains(entity.getUUID())) {
if (createCopy) { if (createCopy) {
copy.storeEntity(entity); copy.storeEntity(entity);
} }
removeEntity(entity); iter.remove();
entitiesRemoved.add(uuid);
entityRemoves.remove(uuid);
}
}
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
for (UUID uuid : entityRemoves) {
Entity entity = nmsWorld.entityManager.getEntityGetter().get(uuid);
if (entity != null) {
removeEntity(entity); removeEntity(entity);
} }
} }
} }
// Only save entities that were actually removed to history }
set.getEntityRemoves().clear();
set.getEntityRemoves().addAll(entitiesRemoved);
}; };
} }
@ -698,9 +672,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
syncTasks[1] = () -> { syncTasks[1] = () -> {
Iterator<CompoundTag> iterator = entities.iterator(); //TODO 1.18 be a CBT & ListBinaryTag ?
while (iterator.hasNext()) { for (final CompoundTag nativeTag : entities) {
final CompoundTag nativeTag = iterator.next();
final Map<String, Tag> entityTagMap = nativeTag.getValue(); final Map<String, Tag> entityTagMap = nativeTag.getValue();
final StringTag idTag = (StringTag) entityTagMap.get("Id"); final StringTag idTag = (StringTag) entityTagMap.get("Id");
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag posTag = (ListTag) entityTagMap.get("Pos");
@ -727,23 +700,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
entity.load(tag); entity.load(tag);
entity.absMoveTo(x, y, z, yaw, pitch); entity.absMoveTo(x, y, z, yaw, pitch);
entity.setUUID(nativeTag.getUUID()); nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
LOGGER.warn(
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
id,
nmsWorld.getWorld().getName(),
x,
y,
z
);
// Unsuccessful create should not be saved to history
iterator.remove();
}
} }
} }
} }
}; };
} }
// set tiles // set tiles
@ -806,6 +768,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
Runnable[] finalSyncTasks = syncTasks; Runnable[] finalSyncTasks = syncTasks;
// Chain the sync tasks and the callback // Chain the sync tasks and the callback
//TODO 1.18 address raw access
Callable<Future> chain = () -> { Callable<Future> chain = () -> {
try { try {
// Run the sync tasks // Run the sync tasks
@ -827,7 +790,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
throw e; throw e;
} }
}; };
//noinspection unchecked - required at compile time
return (T) (Future) queueHandler.sync(chain); return (T) (Future) queueHandler.sync(chain);
} else { } else {
if (callback == null) { if (callback == null) {
@ -907,30 +869,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
* @return the given array to be filled with data, or a new array if null is given. * @return the given array to be filled with data, or a new array if null is given.
*/ */
@Override @Override
@SuppressWarnings("unchecked")
public char[] update(int layer, char[] data, boolean aggressive) { public char[] update(int layer, char[] data, boolean aggressive) {
LevelChunkSection section = getSections(aggressive)[layer]; LevelChunkSection section = getSections(aggressive)[layer];
// Section is null, return empty array // Section is null, return empty array
if (section == null) { if (section == null) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
return data; return data;
} }
if (data != null && data.length != 4096) { if (data != null && data.length != 4096) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
} }
if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) {
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) 1);
} }
Semaphore lock = PaperweightPlatformAdapter.applyLock(section); DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) { synchronized (lock) {
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {
lock.acquire(); lock.acquire();
final PalettedContainer<BlockState> blocks = section.getStates(); final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks);
final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject);
@ -954,7 +915,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {
char paletteVal = data[i]; char paletteVal = data[i];
char ordinal = adapter.ibdIDToOrdinal(paletteVal); char ordinal = adapter.ibdIDToOrdinal(paletteVal);
data[i] = ordinal; // Don't read "empty".
data[i] = ordinal == 0 ? 1 : ordinal;
} }
return data; return data;
} }
@ -973,10 +935,18 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
val = ordinal(palette.valueFor(i), adapter); val = ordinal(palette.valueFor(i), adapter);
paletteToOrdinal[i] = val; paletteToOrdinal[i] = val;
} }
// Don't read "empty".
if (val == 0) {
val = 1;
}
data[i] = val; data[i] = val;
} }
} else { } else {
char ordinal = ordinal(palette.valueFor(0), adapter); char ordinal = ordinal(palette.valueFor(0), adapter);
// Don't read "empty".
if (ordinal == 0) {
ordinal = 1;
}
Arrays.fill(data, ordinal); Arrays.fill(data, ordinal);
} }
} finally { } finally {
@ -994,9 +964,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { private char ordinal(net.minecraft.world.level.block.state.BlockState ibd, PaperweightFaweAdapter adapter) {
if (ibd == null) { if (ibd == null) {
return BlockTypesCache.ReservedIDs.AIR; return 1;
} else { } else {
return adapter.adaptToChar(ibd); return adapter.adaptToChar(ibd);
} }
@ -1073,7 +1043,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private void setBiomesToPalettedContainer( private void setBiomesToPalettedContainer(
final BiomeType[] biomes, final BiomeType[] biomes,
PalettedContainer<Holder<Biome>> data PalettedContainer<Biome> data
) { ) {
int index = 0; int index = 0;
if (biomes == null) { if (biomes == null) {
@ -1090,10 +1060,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }
@ -1107,7 +1074,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
@SuppressWarnings("unchecked")
public synchronized boolean trim(boolean aggressive) { public synchronized boolean trim(boolean aggressive) {
skyLight = new DataLayer[getSectionCount()]; skyLight = new DataLayer[getSectionCount()];
blockLight = new DataLayer[getSectionCount()]; blockLight = new DataLayer[getSectionCount()];
@ -1128,9 +1094,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
LevelChunkSection existing = getSections(true)[layer]; LevelChunkSection existing = getSections(true)[layer];
try { try {
final PalettedContainer<BlockState> blocksExisting = existing.getStates(); final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocksExisting = existing.getStates();
final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting);
//TODO this field doesn't exist in 1.18
final Palette<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.get( final Palette<BlockState> palette = (Palette<BlockState>) PaperweightPlatformAdapter.fieldPalette.get(
dataObject); dataObject);
int paletteSize; int paletteSize;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IBlocks;
@ -8,19 +8,16 @@ import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -38,15 +35,13 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks; private final char[][] blocks;
private final int minHeight; private final int minHeight;
private final int maxHeight; private final int maxHeight;
final ServerLevel serverLevel; private final ServerLevel serverLevel;
final LevelChunk levelChunk; private PalettedContainer<Biome>[] biomes = null;
private PalettedContainer<Holder<Biome>>[] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { protected PaperweightGetBlocks_Copy(ServerLevel world) {
this.levelChunk = levelChunk; this.serverLevel = world;
this.serverLevel = levelChunk.level; this.minHeight = world.getMinBuildHeight();
this.minHeight = serverLevel.getMinBuildHeight(); this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][]; this.blocks = new char[getSectionCount()][];
} }
@ -72,12 +67,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return tiles.get(BlockVector3.at(x, y, z)); return tiles.get(BlockVector3.at(x, y, z));
} }
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) { protected void storeEntity(Entity entity) {
//TODO 1.18 address raw access & possibly be a CBT ?
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag); entities.add((CompoundTag) adapter.toNative(entity.save(compoundTag)));
entities.add((CompoundTag) adapter.toNative(compoundTag));
} }
@Override @Override
@ -88,7 +82,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public CompoundTag getEntity(UUID uuid) { public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) { for (CompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) { 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 tag;
} }
} }
@ -138,8 +143,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2); Biome biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
return PaperweightPlatformAdapter.adapt(biome, serverLevel); return biome != null ? PaperweightPlatformAdapter.adapt(biome, serverLevel) : null;
} }
@Override @Override
@ -165,7 +170,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
blocks[layer] = data; blocks[layer] = data;
} }
protected void storeBiomes(int layer, PalettedContainer<Holder<Biome>> biomeData) { protected void storeBiomes(int layer, PalettedContainer<Biome> biomeData) {
if (biomes == null) { if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()]; biomes = new PalettedContainer[getSectionCount()];
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
@ -10,36 +10,35 @@ import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
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.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap; import net.minecraft.core.IdMap;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ThreadingDetector;
import net.minecraft.util.Unit;
import net.minecraft.util.ZeroBitStorage; import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette; import net.minecraft.world.level.chunk.HashMapPalette;
@ -49,13 +48,13 @@ import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette; import net.minecraft.world.level.chunk.SingleValuePalette;
import org.apache.logging.log4j.Logger; import net.minecraft.world.level.gameevent.GameEventDispatcher;
import org.bukkit.Bukkit; import net.minecraft.world.level.gameevent.GameEventListener;
import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R1.CraftChunk;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -69,12 +68,11 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function; import java.util.function.Function;
public final class PaperweightPlatformAdapter extends NMSAdapter { public final class PaperweightPlatformAdapter extends NMSAdapter {
@ -86,9 +84,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldStorage; public static final Field fieldStorage;
public static final Field fieldPalette; public static final Field fieldPalette;
private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; public static final Field fieldTickingFluidContent;
private static final Field fieldNonEmptyBlockCount; public static final Field fieldTickingBlockCount;
public static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -101,13 +100,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldLock; private static final Field fieldLock;
private static final long fieldLockOffset; private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener; private static final Field fieldGameEventDispatcherSections;
private static final MethodHandle methodremoveTickingBlockEntity; private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldRemove; private static final Field fieldRemove;
private static final Logger LOGGER = LogManagerCompat.getLogger();
static { static {
try { try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d")); fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
@ -117,13 +114,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
dataConstructor = dataClazz.getDeclaredConstructors()[0]; dataConstructor = dataClazz.getDeclaredConstructors()[0];
dataConstructor.setAccessible(true); dataConstructor.setAccessible(true);
//TODO FIXME 1.18
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b")); fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
fieldStorage.setAccessible(true); fieldStorage.setAccessible(true);
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c")); fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true); fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h")); fieldTickingFluidContent = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidContent.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
@ -137,31 +135,19 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
} else {
// in paper, the used methods are synchronized properly
fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null; fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
fieldLockOffset = -1; "gameEventDispatcherSections", "t"));
} fieldGameEventDispatcherSections.setAccessible(true);
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
Refraction.pickName("removeGameEventListener", "d"),
BlockEntity.class
);
removeGameEventListener.setAccessible(true);
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod( Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName( Refraction.pickName(
"removeBlockEntityTicker", "removeBlockEntityTicker",
"l" "m"
), BlockPos.class ), BlockPos.class
); );
removeBlockEntityTicker.setAccessible(true); removeBlockEntityTicker.setAccessible(true);
@ -197,26 +183,17 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return false; return false;
} }
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> SEMAPHORE_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null));
static DelegateSemaphore applyLock(LevelChunkSection section) { static DelegateSemaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates(); PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(blocks,
blocks, fieldThreadingDetectorOffset) ;
fieldThreadingDetectorOffset synchronized(currentThreadingDetector) {
);
synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) { if (currentLock instanceof DelegateSemaphore) {
return delegateSemaphore; return (DelegateSemaphore) currentLock;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);
@ -241,12 +218,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} else { } else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ); LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) { if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk; return nmsChunk;
} }
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ); nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) { if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk; return nmsChunk;
} }
// Avoid "async" methods from the main thread. // Avoid "async" methods from the main thread.
@ -255,21 +230,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true); CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try { try {
CraftChunk chunk; CraftChunk chunk = (CraftChunk) future.get();
try {
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
String world = serverLevel.getWorld().getName();
// We've already taken 10 seconds we can afford to wait a little here.
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
if (loaded) {
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
// Retry chunk load
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
} else {
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
}
}
return chunk.getHandle(); return chunk.getHandle();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -278,13 +239,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)); return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
} }
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket
net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource()
.addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap; ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try { try {
@ -294,7 +248,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
} }
@SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) { if (chunkHolder == null) {
@ -327,7 +280,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
false // last false is to not bother with x-ray false // last false is to not bother with x-ray
); );
} else { } else {
// deprecated on paper - deprecation suppressed // deprecated on paper
//noinspection deprecation
packet = new ClientboundLevelChunkWithLightPacket( packet = new ClientboundLevelChunkWithLightPacket(
levelChunk, levelChunk,
nmsWorld.getChunkSource().getLightEngine(), nmsWorld.getChunkSource().getLightEngine(),
@ -348,22 +302,17 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
NMS conversion NMS conversion
*/ */
public static LevelChunkSection newChunkSection( public static LevelChunkSection newChunkSection(
final int layer, final int layer, final char[] blocks, boolean fastmode,
final char[] blocks, CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
CachedBukkitAdapter adapter, @Nullable PalettedContainer<Biome> biomes
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes); return newChunkSection(layer, null, blocks, fastmode, adapter, biomeRegistry, biomes);
} }
public static LevelChunkSection newChunkSection( public static LevelChunkSection newChunkSection(
final int layer, final int layer, final Function<Integer, char[]> get, char[] set,
final Function<Integer, char[]> get, boolean fastmode, CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
char[] set, @Nullable PalettedContainer<Biome> biomes
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(layer, biomeRegistry, biomes);
@ -373,14 +322,24 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get(); final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get(); final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try { try {
int num_palette; int[] num_palette_buffer = new int[1];
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
int air;
if (get == null) { if (get == null) {
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null); air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
set, ticking_blocks, fastmode, adapter
);
} else { } else {
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null); 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); int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
Object configuration =
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(new FakeIdMapBlock(num_palette), bitsPerEntry);
if (bitsPerEntry > 0 && bitsPerEntry < 5) { if (bitsPerEntry > 0 && bitsPerEntry < 5) {
bitsPerEntry = 4; bitsPerEntry = 4;
} else if (bitsPerEntry > 8) { } else if (bitsPerEntry > 8) {
@ -407,6 +366,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} else { } else {
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits); 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; List<net.minecraft.world.level.block.state.BlockState> palette;
if (bitsPerEntry < 9) { if (bitsPerEntry < 9) {
palette = new ArrayList<>(); palette = new ArrayList<>();
@ -430,68 +390,73 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
nmsBits, nmsBits,
palette palette
); );
LevelChunkSection levelChunkSection;
try {
//fieldStorage.set(dataPaletteBlocks, nmsBits);
//fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
if (biomes == null) { if (biomes == null) {
IdMap<Holder<Biome>> biomeHolderIdMap = biomeRegistry.asHolderIdMap();
biomes = new PalettedContainer<>( biomes = new PalettedContainer<>(
biomeHolderIdMap, biomeRegistry,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeRegistry.getOrThrow(Biomes.PLAINS),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES,
null 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 new LevelChunkSection(layer, blockStatePalettedContainer, biomes); return levelChunkSection;
} catch (final Throwable e) { } catch (final Throwable e) {
throw e;
} finally {
Arrays.fill(blockToPalette, Integer.MAX_VALUE); Arrays.fill(blockToPalette, Integer.MAX_VALUE);
Arrays.fill(paletteToBlock, Integer.MAX_VALUE); throw e;
Arrays.fill(blockStates, 0);
Arrays.fill(blocksCopy, 0);
} }
} }
@SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer, int layer, Registry<Biome> biomeRegistry,
Registry<Biome> biomeRegistry, @Nullable PalettedContainer<Biome> biomes
@Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (biomes == null) {
return new LevelChunkSection(layer, biomeRegistry);
}
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>( PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY, Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(), Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES, PalettedContainer.Strategy.SECTION_STATES,
null null
); );
return new LevelChunkSection(layer, dataPaletteBlocks, biomes); 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. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */
public static PalettedContainer<Holder<Biome>> getBiomePalettedContainer( public static PalettedContainer<Biome> getBiomePalettedContainer(BiomeType[] biomes, Registry<Biome> biomeRegistry) {
BiomeType[] biomes,
IdMap<Holder<Biome>> biomeRegistry
) {
if (biomes == null) { if (biomes == null) {
return null; return null;
} }
BukkitImplAdapter<?> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
// Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length // Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length
Map<BiomeType, Holder<Biome>> palette = new HashMap<>(); Map<BiomeType, Biome> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) { for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Holder<Biome> biome; Biome biome;
if (biomeType == null) { if (biomeType == null) {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS)); biome = biomeRegistry.getOrThrow(Biomes.PLAINS);
} else { } else {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType)); biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()));
} }
palette.put(biomeType, biome); palette.put(biomeType, biome);
} }
@ -504,14 +469,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
if (bitsPerEntry > 3) { if (bitsPerEntry > 3) {
bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1); bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1);
} }
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>( PalettedContainer<Biome> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry, biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), biomeRegistry.getOrThrow(Biomes.PLAINS),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES,
null null
); );
final Palette<Holder<Biome>> biomePalette; final Palette<Biome> biomePalette;
if (bitsPerEntry == 0) { if (bitsPerEntry == 0) {
biomePalette = new SingleValuePalette<>( biomePalette = new SingleValuePalette<>(
biomePalettedContainer.registry, biomePalettedContainer.registry,
@ -563,10 +528,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
if (biomeType == null) { if (biomeType == null) {
continue; continue;
} }
Holder<Biome> biome = biomeRegistry.byId(WorldEditPlugin Biome biome = biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()));
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType));
if (biome == null) { if (biome == null) {
continue; continue;
} }
@ -580,21 +542,24 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return biomePalettedContainer; return biomePalettedContainer;
} }
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException { public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
fieldTickingFluidCount.setShort(section, (short) 0); IllegalAccessException {
fieldTickingBlockCount.setShort(section, (short) 0); fieldTickingFluidContent.setShort(section, (short) 0); // TODO FIXME
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
} }
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) { public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) {
final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY); ResourceLocation resourceLocation = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getKey(
if (biomeRegistry.getKey(biome.value()) == null) { biome);
return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN if (resourceLocation == null) {
return levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY).getId(biome) == -1
? BiomeTypes.OCEAN
: null; : null;
} }
return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString()); return BiomeTypes.get(resourceLocation.toString().toLowerCase(Locale.ROOT));
} }
@SuppressWarnings("unchecked")
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try { try {
// Do the method ourselves to avoid trying to reflect generic method parameters // Do the method ourselves to avoid trying to reflect generic method parameters
@ -603,7 +568,23 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) { if (blockEntity != null) {
if (!levelChunk.level.isClientSide) { if (!levelChunk.level.isClientSide) {
methodRemoveGameEventListener.invoke(levelChunk, beacon); 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); fieldRemove.set(beacon, true);
} }
@ -614,11 +595,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
} }
static List<Entity> getEntities(LevelChunk chunk) { static class FakeIdMapBlock implements IdMap<net.minecraft.world.level.block.state.BlockState> {
return chunk.level.entityManager.getEntities(chunk.getPos());
}
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> { private final int size;
FakeIdMapBlock(int size) {
this.size = size;
}
@Override @Override
public int getId(final net.minecraft.world.level.block.state.BlockState entry) { public int getId(final net.minecraft.world.level.block.state.BlockState entry) {
@ -631,7 +614,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return null; return null;
} }
@Nonnull @Override
public int size() {
return size;
}
@NotNull
@Override @Override
public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() { public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator(); return Collections.emptyIterator();
@ -639,7 +627,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
} }
record FakeIdMapBiome(int size) implements IdMap<Biome> { static class FakeIdMapBiome implements IdMap<Biome> {
private final int size;
FakeIdMapBiome(int size) {
this.size = size;
}
@Override @Override
public int getId(final Biome entry) { public int getId(final Biome entry) {
@ -652,7 +646,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return null; return null;
} }
@Nonnull @Override
public int size() {
return size;
}
@NotNull
@Override @Override
public Iterator<Biome> iterator() { public Iterator<Biome> iterator() {
return Collections.emptyIterator(); return Collections.emptyIterator();

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter; import com.fastasyncworldedit.core.extent.processor.lighting.NMSRelighter;
@ -14,12 +14,16 @@ import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.MCUtil; import net.minecraft.server.MCUtil;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.TicketType; import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit; import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
import org.apache.logging.log4j.Logger; 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.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -31,6 +35,7 @@ import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter implements Relighter { public class PaperweightStarlightRelighter implements Relighter {
public static final MethodHandle RELIGHT;
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32 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 int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting
@ -38,6 +43,26 @@ public class PaperweightStarlightRelighter implements Relighter {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT); 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 ServerLevel serverLevel;
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
@ -45,12 +70,16 @@ public class PaperweightStarlightRelighter implements Relighter {
private final ReentrantLock areaLock = new ReentrantLock(); private final ReentrantLock areaLock = new ReentrantLock();
private final NMSRelighter delegate; private final NMSRelighter delegate;
@SuppressWarnings("rawtypes") //TODO 1.18 address raw access of IQueueChunk
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) { public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<IQueueChunk> queue) {
this.serverLevel = serverLevel; this.serverLevel = serverLevel;
this.delegate = new NMSRelighter(queue); this.delegate = new NMSRelighter(queue);
} }
public static boolean isUsable() {
return RELIGHT != null;
}
@Override @Override
public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) { public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) {
areaLock.lock(); areaLock.lock();
@ -140,9 +169,14 @@ public class PaperweightStarlightRelighter implements Relighter {
IntConsumer processCallback IntConsumer processCallback
) { ) {
try { try {
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); int unused = (int) RELIGHT.invokeExact(
} catch (Exception e) { serverLevel.getChunkSource().getLightEngine(),
LOGGER.error("Error occurred on relighting", e); coords,
chunkCallback, // callback per chunk
processCallback // callback for all chunks
);
} catch (Throwable throwable) {
LOGGER.error("Error occurred on relighting", throwable);
} }
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1; 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.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
@ -8,7 +8,7 @@ import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -16,7 +16,7 @@ public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override @Override
public @Nonnull public @Nonnull
@SuppressWarnings("rawtypes") //TODO 1.18 address raw access of IQueueChunk
Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) { Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName()); org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) { if (w == null) {

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.nbt;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag; import com.sk89q.jnbt.LazyCompoundTag;
@ -35,7 +35,6 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
} }
@Override @Override
@SuppressWarnings("unchecked")
public Map<String, Tag> getValue() { public Map<String, Tag> getValue() {
if (compoundTag == null) { if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
@ -67,8 +66,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public double asDouble(String key) { public double asDouble(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsDouble(); return ((NumericTag) tag).getAsDouble();
} }
return 0; return 0;
} }
@ -87,20 +86,20 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public int asInt(String key) { public int asInt(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsInt(); return ((NumericTag) tag).getAsInt();
} }
return 0; return 0;
} }
@SuppressWarnings("unchecked")
public List<Tag> getList(String key) { public List<Tag> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) { if (tag instanceof net.minecraft.nbt.ListTag) {
ArrayList<Tag> list = new ArrayList<>(); ArrayList<Tag> list = new ArrayList<>();
net.minecraft.nbt.ListTag nbtList = (net.minecraft.nbt.ListTag) tag;
for (net.minecraft.nbt.Tag elem : nbtList) { for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { if (elem instanceof net.minecraft.nbt.CompoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag)); list.add(new PaperweightLazyCompoundTag((net.minecraft.nbt.CompoundTag) elem));
} else { } else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
} }
@ -110,7 +109,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
return Collections.emptyList(); return Collections.emptyList();
} }
@SuppressWarnings("unchecked") //TODO 1.18 be a ListBinaryTag ?
public ListTag getListTag(String key) { public ListTag getListTag(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag) { if (tag instanceof net.minecraft.nbt.ListTag) {
@ -139,8 +138,8 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag {
public long asLong(String key) { public long asLong(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) { if (tag instanceof NumericTag) {
return numTag.getAsLong(); return ((NumericTag) tag).getAsLong();
} }
return 0; return 0;
} }

Datei anzeigen

@ -1,4 +1,4 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.regen; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1.regen;
import com.fastasyncworldedit.bukkit.adapter.Regenerator; import com.fastasyncworldedit.bukkit.adapter.Regenerator;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
@ -9,20 +9,19 @@ import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.PaperweightGetBlocks; 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.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.RegenOptions;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries; import net.minecraft.data.BuiltinRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -34,7 +33,6 @@ import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings; import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
@ -48,16 +46,14 @@ import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldGenSettings; import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.blending.BlendingData; import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.level.storage.PrimaryLevelData;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_18_R1.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.BlockPopulator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -68,7 +64,6 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.OptionalLong;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
@ -79,14 +74,12 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField; private static final Field serverWorldsField;
private static final Field paperConfigField; private static final Field worldPaperConfigField;
private static final Field flatBedrockField; private static final Field flatBedrockField;
private static final Field generatorSettingFlatField; private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField; private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField; private static final Field delegateField;
private static final Field chunkSourceField; private static final Field chunkProviderField;
private static final Field ringPositionsField;
private static final Field hasGeneratedPositionsField;
//list of chunk stati in correct order without FULL //list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>(); private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
@ -130,27 +123,21 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
tmpPaperConfigField = null; tmpPaperConfigField = null;
tmpFlatBedrockField = null; tmpFlatBedrockField = null;
} }
paperConfigField = tmpPaperConfigField; worldPaperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField; flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "h")); "settings", "f"));
generatorSettingBaseSupplierField.setAccessible(true); generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "g")); generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "e"));
generatorSettingFlatField.setAccessible(true); generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true); delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "K")); chunkProviderField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L"));
chunkSourceField.setAccessible(true); chunkProviderField.setAccessible(true);
ringPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("ringPositions", "h"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGenerator.class.getDeclaredField(Refraction.pickName("hasGeneratedPositions", "i"));
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -183,9 +170,9 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
//flat bedrock? (only on paper) //flat bedrock? (only on paper)
if (paperConfigField != null) { if (worldPaperConfigField != null) {
try { try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalServerWorld));
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
@ -197,7 +184,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
@Override @Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception { protected boolean initNewWorld() throws Exception {
//world folder //world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
@ -207,18 +193,17 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment); ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); session = levelStorageSource.createAccess("worldeditregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
BiomeProvider biomeProvider = getBiomeProvider();
MinecraftServer server = originalServerWorld.getCraftServer().getServer(); MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldGenSettings originalOpts = originalWorldData.worldGenSettings(); PrimaryLevelData levelProperties = (PrimaryLevelData) server.getWorldData();
WorldGenSettings originalOpts = levelProperties.worldGenSettings();
WorldGenSettings newOpts = options.getSeed().isPresent() WorldGenSettings newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(originalWorldData.isHardcore(), OptionalLong.of(seed)) ? PaperweightAdapter.replaceSeed(originalServerWorld, seed, originalOpts)
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
originalWorldData.settings.gameType(), originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(), originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(), originalWorldData.settings.difficulty(),
@ -235,28 +220,29 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
session, session,
newWorldData, newWorldData,
originalServerWorld.dimension(), originalServerWorld.dimension(),
originalServerWorld.dimensionTypeRegistration(), originalServerWorld.dimensionType(),
new RegenNoOpWorldLoadListener(), new RegenNoOpWorldLoadListener(),
// placeholder. Required for new ChunkProviderServer, but we create and then set it later // placeholder. Required for new ChunkProviderServer, but we create and then set it later
newOpts.dimensions().getOrThrow(levelStemResourceKey).generator(), newOpts.dimensions().get(levelStemResourceKey).generator(),
originalServerWorld.isDebug(), originalServerWorld.isDebug(),
seed, seed,
ImmutableList.of(), ImmutableList.of(),
false, false,
environment, environment,
generator, generator,
biomeProvider originalBukkitWorld.getBiomeProvider()
) { ) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.asHolderIdMap().byId( private final Biome singleBiome = options.hasBiomeType() ? BuiltinRegistries.BIOME.get(ResourceLocation.tryParse(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) options
) : null; .getBiomeType()
.getId())) : null;
@Override @Override
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
} }
@Override @Override
public Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { public Biome getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) { if (options.hasBiomeType()) {
return singleBiome; return singleBiome;
} }
@ -268,35 +254,25 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
freshWorld.noSave = true; freshWorld.noSave = true;
removeWorldFromWorldsMap(); removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) { if (worldPaperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig); worldPaperConfigField.set(freshWorld, originalServerWorld.paperConfig);
} }
//generator //generator
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); if (originalChunkProvider.getGenerator() instanceof FlatLevelSource flatLevelSource) {
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(originalGenerator.structureSets, generatorSettingFlat); chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { } else if (originalChunkProvider.getGenerator() instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier = Supplier<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Supplier<NoiseGeneratorSettings>) generatorSettingBaseSupplierField
(Holder<NoiseGeneratorSettings>) generatorSettingBaseSupplierField .get(originalChunkProvider.getGenerator());
.get(originalGenerator); BiomeSource biomeSource = originalChunkProvider.getGenerator().getBiomeSource();
BiomeSource biomeSource; chunkGenerator = new NoiseBasedChunkGenerator(noiseBasedChunkGenerator.noises, biomeSource, seed,
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(BuiltinRegistries.BIOME
.asHolderIdMap()
.byId(WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())));
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(originalGenerator.structureSets, noiseBasedChunkGenerator.noises,
biomeSource, seed,
generatorSettingBaseSupplier generatorSettingBaseSupplier
); );
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { } else if (originalChunkProvider.getGenerator() instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.delegate; chunkGenerator = customChunkGenerator.delegate;
} else { } else {
LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); LOGGER.error("Unsupported generator type {}", originalChunkProvider.getGenerator().getClass().getName());
return false; return false;
} }
if (generator != null) { if (generator != null) {
@ -304,21 +280,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
generateConcurrent = generator.isParallelCapable(); generateConcurrent = generator.isParallelCapable();
} }
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(originalGenerator);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> ringPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(
originalGenerator);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(ringPositions);
ringPositionsField.set(chunkGenerator, copy);
hasGeneratedPositionsField.setBoolean(chunkGenerator, true);
}
}
chunkGenerator.conf = originalServerWorld.spigotConfig;
freshChunkProvider = new ServerChunkCache( freshChunkProvider = new ServerChunkCache(
freshWorld, freshWorld,
session, session,
@ -336,16 +297,12 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
) { ) {
// redirect to LevelChunks created in #createChunks // redirect to LevelChunks created in #createChunks
@Override @Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean flag) {
ChunkAccess chunkAccess = getChunkAt(x, z); return getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
} }
}; };
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); ReflectionUtils.unsafeSet(chunkProviderField, freshWorld, freshChunkProvider);
//let's start then //let's start then
structureManager = server.getStructureManager(); structureManager = server.getStructureManager();
threadedLevelLightEngine = freshChunkProvider.getLightEngine(); threadedLevelLightEngine = freshChunkProvider.getLightEngine();
@ -428,12 +385,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
//util //util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() { private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> { Fawe.instance().getQueueHandler().sync(() -> {
try { try {
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>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -441,11 +397,15 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
} }
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) { private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) { switch (env) {
case NETHER -> LevelStem.NETHER; case NETHER:
case THE_END -> LevelStem.END; return LevelStem.NETHER;
default -> LevelStem.OVERWORLD; case THE_END:
}; return LevelStem.END;
case NORMAL:
default:
return LevelStem.OVERWORLD;
}
} }
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {

Datei anzeigen

@ -1,17 +0,0 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
// https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.18.2-R0.1-20220920.010157-167")
compileOnly(libs.paperlib)
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,34 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2;
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();
}
}

Datei anzeigen

@ -1,175 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import javax.annotation.Nullable;
public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@SuppressWarnings("deprecation")
@Override
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
// The PostProcessor shouldn't be added, but just in case
if (!tickFluid) {
return;
}
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
layer:
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
char[] set = iChunkSet.loadIfPresent(layer);
if (set == null) {
// No edit means no need to process
continue;
}
char[] get = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean fromGet = false; // Used for liquids
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (get == null) {
get = getBlocks.load(layer);
}
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
// actually being set
if (get == null) {
continue layer;
}
fromGet = true;
ordinal = replacedOrdinal = get[i];
}
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
continue;
} else if (!fromGet) { // if fromGet, don't do the same again
if (get == null) {
get = getBlocks.load(layer);
}
replacedOrdinal = get[i];
}
boolean ticking = BlockTypesCache.ticking[ordinal];
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
boolean replacedWasLiquid = false;
BlockState replacedState = null;
if (!ticking) {
// If the block being replaced was not ticking, it cannot be a liquid
if (!replacedWasTicking) {
continue;
}
// If the block being replaced is not fluid, we do not need to worry
if (!(replacedWasLiquid =
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
continue;
}
}
BlockState state = BlockState.getFromOrdinal(ordinal);
boolean liquid = state.getMaterial().isLiquid();
int x = i & 15;
int y = (i >> 8) & 15;
int z = (i >> 4) & 15;
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
if (liquid || replacedWasLiquid) {
if (liquid) {
addFluid(getBlocks.serverLevel, state, position);
continue;
}
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
// being ticked anyway. We only need it to be "hit" once.
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
continue;
}
addFluid(getBlocks.serverLevel, replacedState, position);
}
}
}
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
if (set == null || get == null) {
return false;
}
char ordinal;
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
if (x > 0 && set[i - 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
return true;
}
}
if (x < 15 && set[i + 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
return true;
}
}
if (z > 0 && set[i - 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
return true;
}
}
if (z < 15 && set[i + 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
return true;
}
}
if (y > 0 && set[i - 256] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
return true;
}
}
if (y < 15 && set[i + 256] != reserved) {
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isFluid(char ordinal) {
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
}
@SuppressWarnings("deprecation")
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
Fluid type;
if (replacedState.getBlockType() == BlockTypes.LAVA) {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
} else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
}
serverLevel.scheduleTick(
position,
type,
type.getTickDelay(serverLevel)
);
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,16 +0,0 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.19.2-R0.1-20221206.184705-189")
compileOnly(libs.paperlib)
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,248 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk;
this.serverLevel = levelChunk.level;
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
}
protected void storeTile(BlockEntity blockEntity) {
tiles.put(
BlockVector3.at(
blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ()
),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
);
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag));
}
@Override
public Set<CompoundTag> getEntities() {
return this.entities;
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) {
return tag;
}
}
return null;
}
@Override
public boolean isCreateCopy() {
return false;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setHeightmapToGet(HeightMapType type, int[] data) {
}
@Override
public int getMaxY() {
return maxHeight;
}
@Override
public int getMinY() {
return minHeight;
}
@Override
public int getMaxSectionPosition() {
return maxHeight >> 4;
}
@Override
public int getMinSectionPosition() {
return minHeight >> 4;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
return PaperweightPlatformAdapter.adapt(biome, serverLevel);
}
@Override
public void removeSectionLighting(int layer, boolean sky) {
}
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
@Override
public int getSectionCount() {
return serverLevel.getSectionsCount();
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()];
}
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomes[layer] = palettedContainer.copy();
} else {
LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}",
PalettedContainer.class.getSimpleName(),
biomeData.getClass().getSimpleName()
);
}
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(int layer) {
layer -= getMinSectionPosition();
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public char[] loadIfPresent(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = (y >> 4) - getMinSectionPosition();
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

Datei anzeigen

@ -1,703 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
import com.destroystokyo.paper.util.maplist.EntityList;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import io.papermc.paper.world.ChunkEntitySlices;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.BitStorage;
import net.minecraft.util.ExceptionCollector;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector;
import net.minecraft.util.Unit;
import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import net.minecraft.world.level.gameevent.GameEventDispatcher;
import net.minecraft.world.level.gameevent.GameEventListener;
import org.bukkit.craftbukkit.v1_19_R1.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.function.Function;
public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldData;
public static final Constructor<?> dataConstructor;
public static final Field fieldStorage;
public static final Field fieldPalette;
private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock;
private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldRemove;
static final boolean POST_CHUNK_REWRITE;
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
private static Field LEVEL_CHUNK_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER;
static {
try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
fieldData.setAccessible(true);
Class<?> dataClazz = fieldData.getType();
dataConstructor = dataClazz.getDeclaredConstructors()[0];
dataConstructor.setAccessible(true);
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
fieldStorage.setAccessible(true);
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
fieldNonEmptyBlockCount.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent",
"b"
), long.class);
getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
} else {
// in paper, the used methods are synchronized properly
fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null;
fieldLockOffset = -1;
}
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
Refraction.pickName("removeGameEventListener", "a"),
BlockEntity.class,
ServerLevel.class
);
removeGameEventListener.setAccessible(true);
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName(
"removeBlockEntityTicker",
"l"
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
boolean chunkRewrite;
try {
ServerLevel.class.getDeclaredMethod("getEntityLookup");
chunkRewrite = true;
PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities");
PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true);
} catch (NoSuchMethodException ignored) {
chunkRewrite = false;
}
try {
// Paper - Pre-Chunk-Update
LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities");
LEVEL_CHUNK_ENTITIES.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
try {
// Non-Paper
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
POST_CHUNK_REWRITE = chunkRewrite;
} catch (RuntimeException e) {
throw e;
} catch (Throwable rethrow) {
rethrow.printStackTrace();
throw new RuntimeException(rethrow);
}
}
static boolean setSectionAtomic(
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
}
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> SEMAPHORE_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null));
static DelegateSemaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try {
synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(
blocks,
fieldThreadingDetectorOffset
);
synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore;
}
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);
return newLock;
}
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
// Avoid "async" methods from the main thread.
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try {
CraftChunk chunk = (CraftChunk) future.get();
return chunk.getHandle();
} catch (Throwable e) {
e.printStackTrace();
}
}
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource()
.addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try {
return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ));
} catch (Throwable thr) {
throw new RuntimeException(thr);
}
}
@SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) {
return;
}
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
LevelChunk levelChunk;
if (PaperLib.isPaper()) {
// getChunkAtIfLoadedImmediately is paper only
levelChunk = nmsWorld
.getChunkSource()
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
} else {
levelChunk = ((Optional<LevelChunk>) ((Either) chunkHolder
.getTickingChunkFuture() // method is not present with new paper chunk system
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left())
.orElse(null);
}
if (levelChunk == null) {
return;
}
TaskManager.taskManager().task(() -> {
ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true,
false // last false is to not bother with x-ray
);
} else {
// deprecated on paper - deprecation suppressed
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true
);
}
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
});
}
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
}
/*
NMS conversion
*/
public static LevelChunkSection newChunkSection(
final int layer,
final char[] blocks,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
}
public static LevelChunkSection newChunkSection(
final int layer,
final Function<Integer, char[]> get,
char[] set,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes);
}
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try {
int num_palette;
if (get == null) {
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null);
} else {
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null);
}
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
bitsPerEntry = 4;
} else if (bitsPerEntry > 8) {
bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) {
blockStates[i] = 0;
}
} else {
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates);
bitArray.fromRaw(blocksCopy);
}
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
final BitStorage nmsBits;
if (bitsPerEntry == 0) {
nmsBits = new ZeroBitStorage(4096);
} else {
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
}
List<net.minecraft.world.level.block.state.BlockState> palette;
if (bitsPerEntry < 9) {
palette = new ArrayList<>();
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
final BlockState state = BlockTypesCache.states[ordinal];
palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState());
}
} else {
palette = List.of();
}
// Create palette with data
@SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blockStatePalettedContainer =
new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
PalettedContainer.Strategy.SECTION_STATES,
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry),
nmsBits,
palette
);
if (biomes == null) {
IdMap<Holder<Biome>> biomeHolderIdMap = biomeRegistry.asHolderIdMap();
biomes = new PalettedContainer<>(
biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
}
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
} catch (final Throwable e) {
throw e;
} finally {
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
Arrays.fill(paletteToBlock, Integer.MAX_VALUE);
Arrays.fill(blockStates, 0);
Arrays.fill(blocksCopy, 0);
}
}
@SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (biomes == null) {
return new LevelChunkSection(layer, biomeRegistry);
}
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES,
null
);
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
}
/**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/
public static PalettedContainer<Holder<Biome>> getBiomePalettedContainer(
BiomeType[] biomes,
IdMap<Holder<Biome>> biomeRegistry
) {
if (biomes == null) {
return null;
}
BukkitImplAdapter<?> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
// Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length
Map<BiomeType, Holder<Biome>> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Holder<Biome> biome;
if (biomeType == null) {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS));
} else {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType));
}
palette.put(biomeType, biome);
}
int biomeCount = palette.size();
int bitsPerEntry = MathMan.log2nlz(biomeCount - 1);
Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration(
new FakeIdMapBiome(biomeCount),
bitsPerEntry
);
if (bitsPerEntry > 3) {
bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1);
}
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
final Palette<Holder<Biome>> biomePalette;
if (bitsPerEntry == 0) {
biomePalette = new SingleValuePalette<>(
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry == 4) {
biomePalette = LinearPalette.create(
4,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry < 9) {
biomePalette = HashMapPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else {
biomePalette = GlobalPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
null // unused
);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int arrayLength = MathMan.ceilZero(64f / blocksPerLong);
BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage(
bitsPerEntry,
64,
new long[arrayLength]
);
try {
Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette);
fieldData.set(biomePalettedContainer, data);
int index = 0;
for (int y = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = biomes[index];
if (biomeType == null) {
continue;
}
Holder<Biome> biome = biomeRegistry.byId(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType));
if (biome == null) {
continue;
}
biomePalettedContainer.set(x, y, z, biome);
}
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return biomePalettedContainer;
}
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
fieldTickingFluidCount.setShort(section, (short) 0);
fieldTickingBlockCount.setShort(section, (short) 0);
}
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().ownedRegistryOrThrow(Registry.BIOME_REGISTRY);
if (biomeRegistry.getKey(biome.value()) == null) {
return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN
: null;
}
return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString());
}
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try {
if (levelChunk.loaded || levelChunk.level.isClientSide()) {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) {
if (!levelChunk.level.isClientSide) {
methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level);
}
fieldRemove.set(beacon, true);
}
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static List<Entity> getEntities(LevelChunk chunk) {
ExceptionCollector<RuntimeException> collector = new ExceptionCollector<>();
if (PaperLib.isPaper()) {
if (POST_CHUNK_REWRITE) {
try {
//noinspection unchecked
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e);
}
}
try {
EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk);
return List.of(entityList.getRawData());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e));
// fall through
}
}
try {
//noinspection unchecked
return ((PersistentEntitySectionManager<Entity>) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e));
}
collector.throwIfPresent();
return List.of();
}
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {
@Override
public int getId(final net.minecraft.world.level.block.state.BlockState entry) {
return 0;
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator();
}
}
record FakeIdMapBiome(int size) implements IdMap<Biome> {
@Override
public int getId(final Biome entry) {
return 0;
}
@Nullable
@Override
public Biome byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<Biome> iterator() {
return Collections.emptyIterator();
}
}
}

Datei anzeigen

@ -1,175 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R1;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import javax.annotation.Nullable;
public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@SuppressWarnings("deprecation")
@Override
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
// The PostProcessor shouldn't be added, but just in case
if (!tickFluid) {
return;
}
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
layer:
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
char[] set = iChunkSet.loadIfPresent(layer);
if (set == null) {
// No edit means no need to process
continue;
}
char[] get = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean fromGet = false; // Used for liquids
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (get == null) {
get = getBlocks.load(layer);
}
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
// actually being set
if (get == null) {
continue layer;
}
fromGet = true;
ordinal = replacedOrdinal = get[i];
}
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
continue;
} else if (!fromGet) { // if fromGet, don't do the same again
if (get == null) {
get = getBlocks.load(layer);
}
replacedOrdinal = get[i];
}
boolean ticking = BlockTypesCache.ticking[ordinal];
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
boolean replacedWasLiquid = false;
BlockState replacedState = null;
if (!ticking) {
// If the block being replaced was not ticking, it cannot be a liquid
if (!replacedWasTicking) {
continue;
}
// If the block being replaced is not fluid, we do not need to worry
if (!(replacedWasLiquid =
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
continue;
}
}
BlockState state = BlockState.getFromOrdinal(ordinal);
boolean liquid = state.getMaterial().isLiquid();
int x = i & 15;
int y = (i >> 8) & 15;
int z = (i >> 4) & 15;
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
if (liquid || replacedWasLiquid) {
if (liquid) {
addFluid(getBlocks.serverLevel, state, position);
continue;
}
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
// being ticked anyway. We only need it to be "hit" once.
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
continue;
}
addFluid(getBlocks.serverLevel, replacedState, position);
}
}
}
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
if (set == null || get == null) {
return false;
}
char ordinal;
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
if (x > 0 && set[i - 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
return true;
}
}
if (x < 15 && set[i + 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
return true;
}
}
if (z > 0 && set[i - 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
return true;
}
}
if (z < 15 && set[i + 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
return true;
}
}
if (y > 0 && set[i - 256] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
return true;
}
}
if (y < 15 && set[i + 256] != reserved) {
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isFluid(char ordinal) {
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
}
@SuppressWarnings("deprecation")
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
Fluid type;
if (replacedState.getBlockType() == BlockTypes.LAVA) {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
} else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
}
serverLevel.scheduleTick(
position,
type,
type.getTickDelay(serverLevel)
);
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,17 +0,0 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
// https://papermc.io/repo/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.19.3-R0.1-20230312.180621-141")
compileOnly(libs.paperlib)
}

Datei anzeigen

@ -1,93 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
import com.mojang.authlib.GameProfile;
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 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) {
}
}

Datei anzeigen

@ -1,180 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R2;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import java.lang.ref.WeakReference;
import java.util.Objects;
import javax.annotation.Nullable;
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());
}
}
// Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false);
}
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
@Override
public void flush() {
}
}

Datei anzeigen

@ -1,189 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.v1_19_R2.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;
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,248 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk;
this.serverLevel = levelChunk.level;
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
}
protected void storeTile(BlockEntity blockEntity) {
tiles.put(
BlockVector3.at(
blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ()
),
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
);
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag));
}
@Override
public Set<CompoundTag> getEntities() {
return this.entities;
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) {
return tag;
}
}
return null;
}
@Override
public boolean isCreateCopy() {
return false;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setHeightmapToGet(HeightMapType type, int[] data) {
}
@Override
public int getMaxY() {
return maxHeight;
}
@Override
public int getMinY() {
return minHeight;
}
@Override
public int getMaxSectionPosition() {
return maxHeight >> 4;
}
@Override
public int getMinSectionPosition() {
return minHeight >> 4;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
return PaperweightPlatformAdapter.adapt(biome, serverLevel);
}
@Override
public void removeSectionLighting(int layer, boolean sky) {
}
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
@Override
public int getSectionCount() {
return serverLevel.getSectionsCount();
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) {
biomes = new PalettedContainer[getSectionCount()];
}
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomes[layer] = palettedContainer.copy();
} else {
LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}",
PalettedContainer.class.getSimpleName(),
biomeData.getClass().getSimpleName()
);
}
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(int layer) {
layer -= getMinSectionPosition();
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public char[] loadIfPresent(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = (y >> 4) - getMinSectionPosition();
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

Datei anzeigen

@ -1,34 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
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();
}
}

Datei anzeigen

@ -1,700 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
import com.destroystokyo.paper.util.maplist.EntityList;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import io.papermc.paper.world.ChunkEntitySlices;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.BitStorage;
import net.minecraft.util.ExceptionCollector;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector;
import net.minecraft.util.Unit;
import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.bukkit.craftbukkit.v1_19_R2.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.function.Function;
import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldData;
public static final Constructor<?> dataConstructor;
public static final Field fieldStorage;
public static final Field fieldPalette;
private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldThreadingDetector;
private static final long fieldThreadingDetectorOffset;
private static final Field fieldLock;
private static final long fieldLockOffset;
private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldRemove;
static final boolean POST_CHUNK_REWRITE;
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
private static Field LEVEL_CHUNK_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER;
static {
try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
fieldData.setAccessible(true);
Class<?> dataClazz = fieldData.getType();
dataConstructor = dataClazz.getDeclaredConstructors()[0];
dataConstructor.setAccessible(true);
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
fieldStorage.setAccessible(true);
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "h"));
fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
fieldNonEmptyBlockCount.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent",
"b"
), long.class);
getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe();
if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
} else {
// in paper, the used methods are synchronized properly
fieldThreadingDetector = null;
fieldThreadingDetectorOffset = -1;
fieldLock = null;
fieldLockOffset = -1;
}
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
Refraction.pickName("removeGameEventListener", "a"),
BlockEntity.class,
ServerLevel.class
);
removeGameEventListener.setAccessible(true);
methodRemoveGameEventListener = MethodHandles.lookup().unreflect(removeGameEventListener);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName(
"removeBlockEntityTicker",
"l"
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = MethodHandles.lookup().unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true);
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class);
int scale = unsafe.arrayIndexScale(LevelChunkSection[].class);
if ((scale & (scale - 1)) != 0) {
throw new Error("data type scale not a power of two");
}
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
boolean chunkRewrite;
try {
ServerLevel.class.getDeclaredMethod("getEntityLookup");
chunkRewrite = true;
PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities");
PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true);
} catch (NoSuchMethodException ignored) {
chunkRewrite = false;
}
try {
// Paper - Pre-Chunk-Update
LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities");
LEVEL_CHUNK_ENTITIES.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
try {
// Non-Paper
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "P"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
POST_CHUNK_REWRITE = chunkRewrite;
} catch (RuntimeException e) {
throw e;
} catch (Throwable rethrow) {
rethrow.printStackTrace();
throw new RuntimeException(rethrow);
}
}
static boolean setSectionAtomic(
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value);
}
return false;
}
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> SEMAPHORE_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null));
static DelegateSemaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try {
synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe();
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject(
blocks,
fieldThreadingDetectorOffset
);
synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore;
}
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);
return newLock;
}
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
// Avoid "async" methods from the main thread.
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try {
CraftChunk chunk = (CraftChunk) future.get();
return chunk.getHandle();
} catch (Throwable e) {
e.printStackTrace();
}
}
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource()
.addRegionTicket(TicketType.PLUGIN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try {
return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ));
} catch (Throwable thr) {
throw new RuntimeException(thr);
}
}
@SuppressWarnings("deprecation")
public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) {
return;
}
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
LevelChunk levelChunk;
if (PaperLib.isPaper()) {
// getChunkAtIfLoadedImmediately is paper only
levelChunk = nmsWorld
.getChunkSource()
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
} else {
levelChunk = ((Optional<LevelChunk>) ((Either) chunkHolder
.getTickingChunkFuture() // method is not present with new paper chunk system
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left())
.orElse(null);
}
if (levelChunk == null) {
return;
}
TaskManager.taskManager().task(() -> {
ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) {
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true,
false // last false is to not bother with x-ray
);
} else {
// deprecated on paper - deprecation suppressed
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
true
);
}
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
});
}
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
}
/*
NMS conversion
*/
public static LevelChunkSection newChunkSection(
final int layer,
final char[] blocks,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
}
public static LevelChunkSection newChunkSection(
final int layer,
final Function<Integer, char[]> get,
char[] set,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes);
}
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try {
int num_palette;
if (get == null) {
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null);
} else {
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null);
}
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
bitsPerEntry = 4;
} else if (bitsPerEntry > 8) {
bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) {
blockStates[i] = 0;
}
} else {
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates);
bitArray.fromRaw(blocksCopy);
}
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
final BitStorage nmsBits;
if (bitsPerEntry == 0) {
nmsBits = new ZeroBitStorage(4096);
} else {
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
}
List<net.minecraft.world.level.block.state.BlockState> palette;
if (bitsPerEntry < 9) {
palette = new ArrayList<>();
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
final BlockState state = BlockTypesCache.states[ordinal];
palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState());
}
} else {
palette = List.of();
}
// Create palette with data
@SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blockStatePalettedContainer =
new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
PalettedContainer.Strategy.SECTION_STATES,
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry),
nmsBits,
palette
);
if (biomes == null) {
IdMap<Holder<Biome>> biomeHolderIdMap = biomeRegistry.asHolderIdMap();
biomes = new PalettedContainer<>(
biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
}
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
} catch (final Throwable e) {
throw e;
} finally {
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
Arrays.fill(paletteToBlock, Integer.MAX_VALUE);
Arrays.fill(blockStates, 0);
Arrays.fill(blocksCopy, 0);
}
}
@SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (biomes == null) {
return new LevelChunkSection(layer, biomeRegistry);
}
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES,
null
);
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
}
/**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/
public static PalettedContainer<Holder<Biome>> getBiomePalettedContainer(
BiomeType[] biomes,
IdMap<Holder<Biome>> biomeRegistry
) {
if (biomes == null) {
return null;
}
BukkitImplAdapter<?> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
// Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length
Map<BiomeType, Holder<Biome>> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Holder<Biome> biome;
if (biomeType == null) {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS));
} else {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType));
}
palette.put(biomeType, biome);
}
int biomeCount = palette.size();
int bitsPerEntry = MathMan.log2nlz(biomeCount - 1);
Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration(
new FakeIdMapBiome(biomeCount),
bitsPerEntry
);
if (bitsPerEntry > 3) {
bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1);
}
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES,
null
);
final Palette<Holder<Biome>> biomePalette;
if (bitsPerEntry == 0) {
biomePalette = new SingleValuePalette<>(
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry == 4) {
biomePalette = LinearPalette.create(
4,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry < 9) {
biomePalette = HashMapPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else {
biomePalette = GlobalPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
null // unused
);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int arrayLength = MathMan.ceilZero(64f / blocksPerLong);
BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage(
bitsPerEntry,
64,
new long[arrayLength]
);
try {
Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette);
fieldData.set(biomePalettedContainer, data);
int index = 0;
for (int y = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = biomes[index];
if (biomeType == null) {
continue;
}
Holder<Biome> biome = biomeRegistry.byId(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType));
if (biome == null) {
continue;
}
biomePalettedContainer.set(x, y, z, biome);
}
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return biomePalettedContainer;
}
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
fieldTickingFluidCount.setShort(section, (short) 0);
fieldTickingBlockCount.setShort(section, (short) 0);
}
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME);
if (biomeRegistry.getKey(biome.value()) == null) {
return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN
: null;
}
return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString());
}
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try {
if (levelChunk.loaded || levelChunk.level.isClientSide()) {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) {
if (!levelChunk.level.isClientSide) {
methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level);
}
fieldRemove.set(beacon, true);
}
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static List<Entity> getEntities(LevelChunk chunk) {
ExceptionCollector<RuntimeException> collector = new ExceptionCollector<>();
if (PaperLib.isPaper()) {
if (POST_CHUNK_REWRITE) {
try {
//noinspection unchecked
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e);
}
}
try {
EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk);
return List.of(entityList.getRawData());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e));
// fall through
}
}
try {
//noinspection unchecked
return ((PersistentEntitySectionManager<Entity>) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e));
}
collector.throwIfPresent();
return List.of();
}
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {
@Override
public int getId(final net.minecraft.world.level.block.state.BlockState entry) {
return 0;
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator();
}
}
record FakeIdMapBiome(int size) implements IdMap<Biome> {
@Override
public int getId(final Biome entry) {
return 0;
}
@Nullable
@Override
public Biome byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<Biome> iterator() {
return Collections.emptyIterator();
}
}
}

Datei anzeigen

@ -1,175 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import javax.annotation.Nullable;
public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@SuppressWarnings("deprecation")
@Override
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
// The PostProcessor shouldn't be added, but just in case
if (!tickFluid) {
return;
}
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
layer:
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
char[] set = iChunkSet.loadIfPresent(layer);
if (set == null) {
// No edit means no need to process
continue;
}
char[] get = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean fromGet = false; // Used for liquids
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (get == null) {
get = getBlocks.load(layer);
}
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
// actually being set
if (get == null) {
continue layer;
}
fromGet = true;
ordinal = replacedOrdinal = get[i];
}
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
continue;
} else if (!fromGet) { // if fromGet, don't do the same again
if (get == null) {
get = getBlocks.load(layer);
}
replacedOrdinal = get[i];
}
boolean ticking = BlockTypesCache.ticking[ordinal];
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
boolean replacedWasLiquid = false;
BlockState replacedState = null;
if (!ticking) {
// If the block being replaced was not ticking, it cannot be a liquid
if (!replacedWasTicking) {
continue;
}
// If the block being replaced is not fluid, we do not need to worry
if (!(replacedWasLiquid =
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
continue;
}
}
BlockState state = BlockState.getFromOrdinal(ordinal);
boolean liquid = state.getMaterial().isLiquid();
int x = i & 15;
int y = (i >> 8) & 15;
int z = (i >> 4) & 15;
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
if (liquid || replacedWasLiquid) {
if (liquid) {
addFluid(getBlocks.serverLevel, state, position);
continue;
}
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
// being ticked anyway. We only need it to be "hit" once.
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
continue;
}
addFluid(getBlocks.serverLevel, replacedState, position);
}
}
}
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
if (set == null || get == null) {
return false;
}
char ordinal;
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
if (x > 0 && set[i - 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
return true;
}
}
if (x < 15 && set[i + 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
return true;
}
}
if (z > 0 && set[i - 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
return true;
}
}
if (z < 15 && set[i + 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
return true;
}
}
if (y > 0 && set[i - 256] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
return true;
}
}
if (y < 15 && set[i + 256] != reserved) {
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isFluid(char ordinal) {
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
}
@SuppressWarnings("deprecation")
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
Fluid type;
if (replacedState.getBlockType() == BlockTypes.LAVA) {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
} else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
}
serverLevel.scheduleTick(
position,
type,
type.getTickDelay(serverLevel)
);
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,594 +0,0 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.regen;
import com.fastasyncworldedit.bukkit.adapter.Regenerator;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R2.PaperweightGetBlocks;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.thread.ProcessorHandle;
import net.minecraft.util.thread.ProcessorMailbox;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R2.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field flatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
private static final Field generatorStructureStateField;
private static final Field ringPositionsField;
private static final Field hasGeneratedPositionsField;
//list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.FULL
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(
ChunkStatus.LIQUID_CARVERS,
Concurrency.NONE
); // liquid carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "L"));
chunkSourceField.setAccessible(true);
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w"));
generatorStructureStateField.setAccessible(true);
ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(
Refraction.pickName("hasGeneratedPositions", "h")
);
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureTemplateManager structureTemplateManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
if (!(originalChunkProvider instanceof ServerChunkCache)) {
return false;
}
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
.getOrThrow(levelStemResourceKey),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
}
@Override
public Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
);
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
}
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator();
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Holder<NoiseGeneratorSettings>) generatorSettingBaseSupplierField.get(
originalGenerator);
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(
DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
)
);
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(
biomeSource,
generatorSettingBaseSupplier
);
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.getDelegate();
} else {
LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName());
return false;
}
if (generator != null) {
chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator);
generateConcurrent = generator.isParallelCapable();
}
// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed
freshChunkProvider = new ServerChunkCache(
freshWorld,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
freshWorld.spigotConfig.simulationDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap);
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> origPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(state);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(
origPositions);
ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap);
ringPositionsField.set(newState, copy);
hasGeneratedPositionsField.setBoolean(newState, true);
}
}
ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider);
//let's start then
structureTemplateManager = server.getStructureManager();
threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider);
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld,
this.freshWorld.registryAccess().registryOrThrow(BIOME), null
);
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> blockPopulator.populate(freshWorld.getWorld(), random, levelChunk.getBukkitChunk()));
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
Fawe.instance().getQueueHandler().sync(() -> {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
public FastProtoChunk(
final ChunkPos pos,
final UpgradeData upgradeData,
final LevelHeightAccessor world,
final Registry<Biome> biomeRegistry,
@Nullable final BlendingData blendingData
) {
super(pos, upgradeData, world, biomeRegistry, blendingData);
}
// avoid warning on paper
// compatibility with spigot
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return chunkStatus.getRange();
}
@Override
public String name() {
return chunkStatus.getName();
}
@Override
public CompletableFuture<?> processChunk(Long xz, List<ChunkAccess> accessibleChunks) {
return chunkStatus.generate(
Runnable::run, // TODO revisit, we might profit from this somehow?
freshWorld,
chunkGenerator,
structureTemplateManager,
threadedLevelLightEngine,
c -> CompletableFuture.completedFuture(Either.left(c)),
accessibleChunks,
true
);
}
}
/**
* A light engine that does nothing. As light is calculated after pasting anyway, we can avoid
* work this way.
*/
static class NoOpLightEngine extends ThreadedLevelLightEngine {
private static final ProcessorMailbox<Runnable> MAILBOX = ProcessorMailbox.create(task -> {
}, "fawe-no-op");
private static final ProcessorHandle<Message<Runnable>> HANDLE = ProcessorHandle.of("fawe-no-op", m -> {
});
public NoOpLightEngine(final ServerChunkCache chunkProvider) {
super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE);
}
@Override
public CompletableFuture<ChunkAccess> retainData(final ChunkAccess chunk) {
return CompletableFuture.completedFuture(chunk);
}
@Override
public CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) {
return CompletableFuture.completedFuture(chunk);
}
}
}

Datei anzeigen

@ -1,16 +0,0 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.19.4-R0.1-20230608.201059-104")
compileOnly(libs.paperlib)
}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen