mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Merge remote-tracking branch 'refs/remotes/upstream/master' into end-void
# Conflicts: # core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java
This commit is contained in:
commit
c496680289
309 changed files with 12400 additions and 43130 deletions
89
.github/workflows/build-remote.yml
vendored
89
.github/workflows/build-remote.yml
vendored
|
|
@ -22,81 +22,26 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Setup Gradle
|
||||||
# See https://github.com/actions/setup-java/commits
|
uses: GeyserMC/actions/setup-gradle-composite@master
|
||||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
checkout_repository: ${{ inputs.repository }}
|
||||||
distribution: temurin
|
checkout_ref: ${{ inputs.ref }}
|
||||||
|
setup-java_java-version: 21
|
||||||
- name: Checkout repository and submodules
|
setup-gradle_cache-read-only: true
|
||||||
# See https://github.com/actions/checkout/commits
|
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
||||||
with:
|
|
||||||
repository: ${{ inputs.repository }}
|
|
||||||
ref: ${{ inputs.ref }}
|
|
||||||
submodules: recursive
|
|
||||||
path: geyser
|
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
|
||||||
# See https://github.com/gradle/wrapper-validation-action/commits
|
|
||||||
uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1
|
|
||||||
|
|
||||||
- name: Build Geyser
|
- name: Build Geyser
|
||||||
# See https://github.com/gradle/actions/commits
|
run: ./gradlew build
|
||||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
|
|
||||||
with:
|
|
||||||
arguments: build
|
|
||||||
build-root-directory: geyser
|
|
||||||
cache-read-only: true
|
|
||||||
|
|
||||||
- name: Archive artifacts (Geyser Fabric)
|
- name: Archive Artifacts
|
||||||
# See https://github.com/actions/upload-artifact/commits
|
uses: GeyserMC/actions/upload-multi-artifact@master
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
artifacts: |
|
||||||
path: geyser/bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||||
if-no-files-found: error
|
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||||
- name: Archive artifacts (Geyser NeoForge)
|
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||||
if: success()
|
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||||
with:
|
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||||
name: Geyser NeoForge
|
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||||
path: geyser/bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Standalone
|
|
||||||
path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Spigot)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Spigot
|
|
||||||
path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser BungeeCord)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser BungeeCord
|
|
||||||
path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Velocity)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Velocity
|
|
||||||
path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser ViaProxy)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser ViaProxy
|
|
||||||
path: geyser/bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
191
.github/workflows/build.yml
vendored
191
.github/workflows/build.yml
vendored
|
|
@ -21,103 +21,55 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
PROJECT: 'geyser'
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set Build Number
|
- name: Get Release Info
|
||||||
|
id: release-info
|
||||||
|
uses: GeyserMC/actions/previous-release@master
|
||||||
|
with:
|
||||||
|
data: ${{ vars.RELEASEACTION_PREVRELEASE }}
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: GeyserMC/actions/setup-gradle-composite@master
|
||||||
|
with:
|
||||||
|
setup-java_java-version: 21
|
||||||
|
|
||||||
|
- name: Build Geyser
|
||||||
|
run: ./gradlew build
|
||||||
env:
|
env:
|
||||||
BUILD_JSON: ${{ vars.RELEASEACTION_PREVRELEASE }}
|
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||||
run: |
|
|
||||||
BUILD_NUMBER=$(echo $BUILD_JSON | jq --arg branch "${GITHUB_REF_NAME}" 'if .[$branch] == null then 1 else .[$branch] | .t | tonumber + 1 end // 1')
|
|
||||||
echo "BUILD_NUMBER=${BUILD_NUMBER:=$GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout repository and submodules
|
|
||||||
# See https://github.com/actions/checkout/commits
|
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
|
||||||
# See https://github.com/gradle/wrapper-validation-action/commits
|
|
||||||
uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1
|
|
||||||
|
|
||||||
# See https://github.com/actions/setup-java/commits
|
|
||||||
- uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
|
||||||
with:
|
|
||||||
java-version: 21
|
|
||||||
distribution: temurin
|
|
||||||
|
|
||||||
- name: Build
|
- name: Archive Artifacts
|
||||||
# See https://github.com/gradle/actions/commits
|
uses: GeyserMC/actions/upload-multi-artifact@master
|
||||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
|
|
||||||
with:
|
|
||||||
arguments: build
|
|
||||||
gradle-home-cache-cleanup: true
|
|
||||||
|
|
||||||
- name: Archive artifacts (Geyser Fabric)
|
|
||||||
# See https://github.com/actions/upload-artifact/commits
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
artifacts: |
|
||||||
path: bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||||
if-no-files-found: error
|
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||||
- name: Archive artifacts (Geyser NeoForge)
|
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||||
if: success()
|
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||||
with:
|
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||||
name: Geyser NeoForge
|
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||||
path: bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Standalone
|
|
||||||
path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Spigot)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Spigot
|
|
||||||
path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser BungeeCord)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser BungeeCord
|
|
||||||
path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Velocity)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Velocity
|
|
||||||
path: bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser ViaProxy)
|
|
||||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser ViaProxy
|
|
||||||
path: bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Publish to Maven Repository
|
- name: Publish to Maven Repository
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
run: ./gradlew publish
|
||||||
env:
|
env:
|
||||||
|
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||||
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
|
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
|
||||||
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
|
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
|
||||||
with:
|
|
||||||
arguments: publish
|
- name: Get Version
|
||||||
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||||
|
id: get-version
|
||||||
|
run: |
|
||||||
|
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
||||||
|
echo "VERSION=${version}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Get Release Metadata
|
- name: Get Release Metadata
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||||
# See https://github.com/Kas-tle/base-release-action/releases/tag/main-11
|
uses: GeyserMC/actions/release@master
|
||||||
uses: Kas-tle/base-release-action@b863fa0f89bd15267a96a72efb84aec25f168d4c # main-11
|
id: metadata
|
||||||
with:
|
with:
|
||||||
appID: ${{ secrets.RELEASE_APP_ID }}
|
appID: ${{ secrets.RELEASE_APP_ID }}
|
||||||
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
|
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
|
||||||
|
|
@ -131,61 +83,38 @@ jobs:
|
||||||
viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||||
releaseEnabled: false
|
releaseEnabled: false
|
||||||
saveMetadata: true
|
saveMetadata: true
|
||||||
- name: Update Generated Metadata
|
releaseProject: 'geyser'
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
releaseVersion: ${{ steps.get-version.outputs.VERSION }}
|
||||||
run: |
|
|
||||||
cat metadata.json
|
|
||||||
echo
|
|
||||||
mv metadata.json metadata.json.tmp
|
|
||||||
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
|
||||||
jq --arg project "${PROJECT}" --arg version "${version}" '
|
|
||||||
.
|
|
||||||
| .changes |= map({"commit", "summary", "message"})
|
|
||||||
| .downloads |= map_values({"name", "sha256"})
|
|
||||||
| {$project, "repo", $version, "number": .build, "changes", "downloads"}
|
|
||||||
' metadata.json.tmp > metadata.json
|
|
||||||
cat metadata.json
|
|
||||||
- name: Publish to Downloads API
|
- name: Publish to Downloads API
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||||
shell: bash
|
uses: GeyserMC/actions/upload-release@master
|
||||||
env:
|
with:
|
||||||
DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
|
username: ${{ vars.DOWNLOADS_USERNAME }}
|
||||||
DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
|
privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
|
||||||
DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
|
host: ${{ secrets.DOWNLOADS_SERVER_IP }}
|
||||||
run: |
|
files: |
|
||||||
# Save the private key to a file
|
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||||
echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
|
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||||
chmod 600 id_ecdsa
|
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||||
# Create the build folder
|
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||||
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/"
|
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
# Copy over artifacts
|
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/
|
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/mod/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/
|
changelog: ${{ steps.metadata.outputs.body }}
|
||||||
# Run the build script
|
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$GITHUB_RUN_NUMBER/
|
|
||||||
|
|
||||||
- name: Publish to Modrinth (Fabric)
|
- name: Publish to Modrinth
|
||||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||||
env:
|
env:
|
||||||
|
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
with:
|
run: ./gradlew modrinth
|
||||||
arguments: fabric:modrinth
|
|
||||||
gradle-home-cache-cleanup: true
|
|
||||||
|
|
||||||
- name: Publish to Modrinth (NeoForge)
|
|
||||||
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
|
||||||
env:
|
|
||||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
|
||||||
with:
|
|
||||||
arguments: neoforge:modrinth
|
|
||||||
gradle-home-cache-cleanup: true
|
|
||||||
|
|
||||||
- name: Notify Discord
|
- name: Notify Discord
|
||||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||||
# See https://github.com/Tim203/actions-git-discord-webhook/commits
|
uses: GeyserMC/actions/notify-discord@master
|
||||||
uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
|
|
||||||
with:
|
with:
|
||||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
|
discordWebhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
status: ${{ job.status }}
|
status: ${{ job.status }}
|
||||||
|
body: ${{ steps.metadata.outputs.body }}
|
||||||
|
includeDownloads: ${{ github.ref_name == 'master' }}
|
||||||
|
|
|
||||||
33
.github/workflows/dispatch-preview.yml
vendored
Normal file
33
.github/workflows/dispatch-preview.yml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
name: Dispatch Preview
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
runId:
|
||||||
|
required: true
|
||||||
|
description: 'ID of the action to pull artifacts from'
|
||||||
|
build:
|
||||||
|
required: true
|
||||||
|
description: 'Build number for the release'
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
description: 'Version under which to upload to the Downloads API'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch-preview:
|
||||||
|
# Allow access to secrets if we are uploading a preview
|
||||||
|
secrets: inherit
|
||||||
|
uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
|
||||||
|
with:
|
||||||
|
build: ${{ inputs.build }}
|
||||||
|
version: ${{ inputs.version }}
|
||||||
|
files: |
|
||||||
|
bungeecord:Geyser-BungeeCord.jar
|
||||||
|
fabric:Geyser-Fabric.jar
|
||||||
|
neoforge:Geyser-NeoForge.jar
|
||||||
|
spigot:Geyser-Spigot.jar
|
||||||
|
standalone:Geyser-Standalone.jar
|
||||||
|
velocity:Geyser-Velocity.jar
|
||||||
|
viaproxy:Geyser-ViaProxy.jar
|
||||||
|
project: geyserpreview
|
||||||
|
runId: ${{ inputs.runId }}
|
||||||
96
.github/workflows/preview.yml
vendored
96
.github/workflows/preview.yml
vendored
|
|
@ -1,96 +0,0 @@
|
||||||
name: Upload Preview
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
runId:
|
|
||||||
required: true
|
|
||||||
description: 'ID of the action to pull artifacts from'
|
|
||||||
build:
|
|
||||||
required: true
|
|
||||||
description: 'Build number for the release'
|
|
||||||
version:
|
|
||||||
required: true
|
|
||||||
description: 'Version under which to upload to the Downloads API'
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
build:
|
|
||||||
required: true
|
|
||||||
description: 'Build number for the release'
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
required: true
|
|
||||||
description: 'Version under which to upload to the Downloads API'
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
upload:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
PROJECT: 'geyserpreview'
|
|
||||||
steps:
|
|
||||||
- name: Set Variables
|
|
||||||
id: setvars
|
|
||||||
run: |
|
|
||||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
|
||||||
echo "BUILD=${{ github.event.inputs.build }}" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
|
||||||
echo "RUN=${{ github.event.inputs.runId }}" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "BUILD=${{ inputs.build }}" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV
|
|
||||||
echo "RUN=${{ github.run_id }}" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
- uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427
|
|
||||||
with:
|
|
||||||
run-id: ${{ steps.setvars.outputs.RUN }}
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
merge-multiple: true
|
|
||||||
- name: Get Preview Metadata
|
|
||||||
if: success()
|
|
||||||
# See https://github.com/Kas-tle/base-release-action/releases/tag/main-11
|
|
||||||
uses: Kas-tle/base-release-action@664c39985eb9d0d393ce98e7eb8414d3d98e762a # main-11
|
|
||||||
with:
|
|
||||||
appID: ${{ secrets.RELEASE_APP_ID }}
|
|
||||||
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
|
|
||||||
files: |
|
|
||||||
bungeecord:Geyser-BungeeCord.jar
|
|
||||||
fabric:Geyser-Fabric.jar
|
|
||||||
neoforge:Geyser-NeoForge.jar
|
|
||||||
spigot:Geyser-Spigot.jar
|
|
||||||
standalone:Geyser-Standalone.jar
|
|
||||||
velocity:Geyser-Velocity.jar
|
|
||||||
viaproxy:Geyser-ViaProxy.jar
|
|
||||||
releaseEnabled: false
|
|
||||||
saveMetadata: true
|
|
||||||
updateReleaseData: false
|
|
||||||
- name: Update Generated Metadata
|
|
||||||
if: success()
|
|
||||||
run: |
|
|
||||||
cat metadata.json
|
|
||||||
echo
|
|
||||||
mv metadata.json metadata.json.tmp
|
|
||||||
jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" '
|
|
||||||
.
|
|
||||||
| .downloads |= map_values({"name", "sha256"})
|
|
||||||
| {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"}
|
|
||||||
' metadata.json.tmp > metadata.json
|
|
||||||
cat metadata.json
|
|
||||||
- name: Publish to Downloads API
|
|
||||||
if: success()
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
|
|
||||||
DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
|
|
||||||
DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
|
|
||||||
run: |
|
|
||||||
# Save the private key to a file
|
|
||||||
echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
|
|
||||||
chmod 600 id_ecdsa
|
|
||||||
# Create the build folder
|
|
||||||
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$PROJECT/$BUILD/"
|
|
||||||
# Copy over artifacts
|
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/
|
|
||||||
# Run the build script
|
|
||||||
# Push the metadata
|
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$PROJECT/$BUILD/
|
|
||||||
16
.github/workflows/pull-request.yml
vendored
16
.github/workflows/pull-request.yml
vendored
|
|
@ -8,7 +8,7 @@ jobs:
|
||||||
# Forbid access to secrets nor GH Token perms while building the PR
|
# Forbid access to secrets nor GH Token perms while building the PR
|
||||||
permissions: {}
|
permissions: {}
|
||||||
secrets: {}
|
secrets: {}
|
||||||
uses: ./.github/workflows/build-remote.yml
|
uses: GeyserMC/Geyser/.github/workflows/build-remote.yml@master
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
@ -18,7 +18,17 @@ jobs:
|
||||||
contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
|
contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
|
||||||
# Allow access to secrets if we are uploading a preview
|
# Allow access to secrets if we are uploading a preview
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
uses: ./.github/workflows/preview.yml
|
uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
|
||||||
with:
|
with:
|
||||||
build: ${{ github.run_number }}
|
build: ${{ github.run_number }}
|
||||||
version: pr.${{ github.event.pull_request.number }}
|
version: pr.${{ github.event.pull_request.number }}
|
||||||
|
files: |
|
||||||
|
bungeecord:Geyser-BungeeCord.jar
|
||||||
|
fabric:Geyser-Fabric.jar
|
||||||
|
neoforge:Geyser-NeoForge.jar
|
||||||
|
spigot:Geyser-Spigot.jar
|
||||||
|
standalone:Geyser-Standalone.jar
|
||||||
|
velocity:Geyser-Velocity.jar
|
||||||
|
viaproxy:Geyser-ViaProxy.jar
|
||||||
|
project: geyserpreview
|
||||||
|
runId: ${{ github.run_id }}
|
||||||
|
|
@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
||||||
|
|
||||||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
|
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
|
||||||
|
|
||||||
### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.80/81 and Minecraft Java 1.20.5/1.20.6
|
### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.21
|
||||||
|
|
||||||
## Setting Up
|
## Setting Up
|
||||||
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
|
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
|
||||||
|
|
|
||||||
|
|
@ -145,4 +145,36 @@ public interface CameraData {
|
||||||
* @return whether the camera is currently locked
|
* @return whether the camera is currently locked
|
||||||
*/
|
*/
|
||||||
boolean isCameraLocked();
|
boolean isCameraLocked();
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Hides a {@link GuiElement} on the client's side.
|
||||||
|
*
|
||||||
|
* @param element the {@link GuiElement} to hide
|
||||||
|
*/
|
||||||
|
void hideElement(@NonNull GuiElement... element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets a {@link GuiElement} on the client's side.
|
||||||
|
* This makes the client decide on its own - e.g. based on client settings -
|
||||||
|
* whether to show or hide the gui element.
|
||||||
|
* <p>
|
||||||
|
* If no elements are specified, this will reset all currently hidden elements
|
||||||
|
*
|
||||||
|
* @param element the {@link GuiElement} to reset
|
||||||
|
*/
|
||||||
|
void resetElement(@NonNull GuiElement @Nullable... element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a {@link GuiElement} is currently hidden.
|
||||||
|
*
|
||||||
|
* @param element the {@link GuiElement} to check
|
||||||
|
*/
|
||||||
|
boolean isHudElementHidden(@NonNull GuiElement element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently hidden {@link GuiElement}s.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable view of all currently hidden {@link GuiElement}s
|
||||||
|
*/
|
||||||
|
@NonNull Set<GuiElement> hiddenElements();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.bedrock.camera;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent GUI elements on the players HUD display.
|
||||||
|
* These can be hidden using {@link CameraData#hideElement(GuiElement...)},
|
||||||
|
* and one can reset their visibility using {@link CameraData#resetElement(GuiElement...)}.
|
||||||
|
*/
|
||||||
|
public class GuiElement {
|
||||||
|
public static final GuiElement PAPER_DOLL = new GuiElement(0);
|
||||||
|
public static final GuiElement ARMOR = new GuiElement(1);
|
||||||
|
public static final GuiElement TOOL_TIPS = new GuiElement(2);
|
||||||
|
public static final GuiElement TOUCH_CONTROLS = new GuiElement(3);
|
||||||
|
public static final GuiElement CROSSHAIR = new GuiElement(4);
|
||||||
|
public static final GuiElement HOTBAR = new GuiElement(5);
|
||||||
|
public static final GuiElement HEALTH = new GuiElement(6);
|
||||||
|
public static final GuiElement PROGRESS_BAR = new GuiElement(7);
|
||||||
|
public static final GuiElement FOOD_BAR = new GuiElement(8);
|
||||||
|
public static final GuiElement AIR_BUBBLES_BAR = new GuiElement(9);
|
||||||
|
public static final GuiElement VEHICLE_HEALTH = new GuiElement(10);
|
||||||
|
public static final GuiElement EFFECTS_BAR = new GuiElement(11);
|
||||||
|
public static final GuiElement ITEM_TEXT_POPUP = new GuiElement(12);
|
||||||
|
|
||||||
|
private GuiElement(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal use only; don't depend on these values being consistent.
|
||||||
|
*/
|
||||||
|
public int id() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a session has logged in, and is about to connect to a remote java server.
|
* Called when a session has logged in, and is about to connect to a remote Java server.
|
||||||
* This event is cancellable, and can be used to prevent the player from connecting to the remote server.
|
* This event is cancellable, and can be used to prevent the player from connecting to the remote server.
|
||||||
*/
|
*/
|
||||||
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
|
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
|
||||||
|
|
@ -99,9 +99,9 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link RemoteServer} the section will attempt to connect to.
|
* Gets the {@link RemoteServer} the session will attempt to connect to.
|
||||||
*
|
*
|
||||||
* @return the {@link RemoteServer} the section will attempt to connect to.
|
* @return the {@link RemoteServer} the session will attempt to connect to.
|
||||||
*/
|
*/
|
||||||
public @NonNull RemoteServer remoteServer() {
|
public @NonNull RemoteServer remoteServer() {
|
||||||
return this.remoteServer;
|
return this.remoteServer;
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modrinth {
|
||||||
|
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||||
|
loaders.add("bungeecord")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,22 +26,19 @@
|
||||||
package org.geysermc.geyser.platform.bungeecord;
|
package org.geysermc.geyser.platform.bungeecord;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class GeyserBungeeLogger implements GeyserLogger {
|
public class GeyserBungeeLogger implements GeyserLogger {
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
|
|
||||||
public GeyserBungeeLogger(Logger logger, boolean debug) {
|
|
||||||
this.logger = logger;
|
|
||||||
this.debug = debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void severe(String message) {
|
public void severe(String message) {
|
||||||
logger.severe(message);
|
logger.severe(message);
|
||||||
|
|
|
||||||
|
|
@ -58,14 +58,13 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserBungeeConfiguration geyserConfig;
|
private GeyserBungeeConfiguration geyserConfig;
|
||||||
private GeyserBungeeInjector geyserInjector;
|
private GeyserBungeeInjector geyserInjector;
|
||||||
private GeyserBungeeLogger geyserLogger;
|
private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
|
||||||
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||||
|
|
||||||
private GeyserImpl geyser;
|
private GeyserImpl geyser;
|
||||||
|
|
@ -82,21 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
// Copied from ViaVersion.
|
// Copied from ViaVersion.
|
||||||
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
|
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
|
||||||
try {
|
try {
|
||||||
ProtocolConstants.class.getField("MINECRAFT_1_20_3");
|
ProtocolConstants.class.getField("MINECRAFT_1_21");
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
getLogger().warning(" / \\");
|
geyserLogger.error(" / \\");
|
||||||
getLogger().warning(" / \\");
|
geyserLogger.error(" / \\");
|
||||||
getLogger().warning(" / | \\");
|
geyserLogger.error(" / | \\");
|
||||||
getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
|
geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
|
||||||
getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||||
getLogger().warning(" / o \\");
|
geyserLogger.error(" / o \\");
|
||||||
getLogger().warning("/_____________\\");
|
geyserLogger.error("/_____________\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.loadConfig()) {
|
if (!this.loadConfig()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
|
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
|
||||||
this.geyserInjector = new GeyserBungeeInjector(this);
|
this.geyserInjector = new GeyserBungeeInjector(this);
|
||||||
|
|
@ -293,7 +292,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,13 @@ loom {
|
||||||
mixin.defaultRefmapName.set("geyser-refmap.json")
|
mixin.defaultRefmapName.set("geyser-refmap.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
// We don't need these
|
||||||
|
tasks.named("remapModrinthJar").configure {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
compileOnly(libs.mixin)
|
compileOnly(libs.mixin)
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ tasks {
|
||||||
|
|
||||||
modrinth {
|
modrinth {
|
||||||
loaders.add("fabric")
|
loaders.add("fabric")
|
||||||
|
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||||
dependencies {
|
dependencies {
|
||||||
required.project("fabric-api")
|
required.project("fabric-api")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@
|
||||||
"geyser.mixins.json"
|
"geyser.mixins.json"
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.15.10",
|
"fabricloader": ">=0.15.11",
|
||||||
"fabric": "*",
|
"fabric": "*",
|
||||||
"minecraft": ">=1.20.5"
|
"minecraft": ">=1.21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,5 @@ tasks {
|
||||||
|
|
||||||
modrinth {
|
modrinth {
|
||||||
loaders.add("neoforge")
|
loaders.add("neoforge")
|
||||||
|
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||||
}
|
}
|
||||||
|
|
@ -14,12 +14,12 @@ config = "geyser.mixins.json"
|
||||||
[[dependencies.geyser_neoforge]]
|
[[dependencies.geyser_neoforge]]
|
||||||
modId="neoforge"
|
modId="neoforge"
|
||||||
type="required"
|
type="required"
|
||||||
versionRange="[20.5.0-beta,)"
|
versionRange="[21.0.0-beta,)"
|
||||||
ordering="NONE"
|
ordering="NONE"
|
||||||
side="BOTH"
|
side="BOTH"
|
||||||
[[dependencies.geyser_neoforge]]
|
[[dependencies.geyser_neoforge]]
|
||||||
modId="minecraft"
|
modId="minecraft"
|
||||||
type="required"
|
type="required"
|
||||||
versionRange="[1.20.5,1.21)"
|
versionRange="[1.21,)"
|
||||||
ordering="NONE"
|
ordering="NONE"
|
||||||
side="BOTH"
|
side="BOTH"
|
||||||
|
|
@ -34,7 +34,6 @@ import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
|
|
@ -80,7 +79,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserModConfiguration geyserConfig;
|
private GeyserModConfiguration geyserConfig;
|
||||||
private GeyserModInjector geyserInjector;
|
private GeyserModInjector geyserInjector;
|
||||||
private GeyserModLogger geyserLogger;
|
private final GeyserModLogger geyserLogger = new GeyserModLogger();
|
||||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
private WorldManager geyserWorldManager;
|
private WorldManager geyserWorldManager;
|
||||||
|
|
||||||
|
|
@ -92,7 +91,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||||
if (!loadConfig()) {
|
if (!loadConfig()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.geyserLogger = new GeyserModLogger(geyserConfig.isDebugMode());
|
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
this.geyser = GeyserImpl.load(this.platform.platformType(), this);
|
this.geyser = GeyserImpl.load(this.platform.platformType(), this);
|
||||||
|
|
||||||
|
|
@ -288,7 +287,7 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LogManager.getLogger("geyser").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,6 @@ public class GeyserModLogger implements GeyserLogger {
|
||||||
|
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
|
|
||||||
public GeyserModLogger(boolean isDebug) {
|
|
||||||
debug = isDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void severe(String message) {
|
public void severe(String message) {
|
||||||
logger.fatal(message);
|
logger.fatal(message);
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.mod.world;
|
package org.geysermc.geyser.platform.mod.world;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
|
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
|
||||||
import net.minecraft.SharedConstants;
|
import net.minecraft.SharedConstants;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
|
@ -39,33 +33,26 @@ import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.server.network.Filterable;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.WritableBookContent;
|
|
||||||
import net.minecraft.world.item.component.WrittenBookContent;
|
|
||||||
import net.minecraft.world.level.Level;
|
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.BannerBlockEntity;
|
import net.minecraft.world.level.block.entity.BannerBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BannerPatternLayers;
|
import net.minecraft.world.level.block.entity.BannerPatternLayers;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
|
||||||
import org.geysermc.erosion.util.LecternUtils;
|
|
||||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
import org.geysermc.geyser.util.MinecraftKey;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
@ -73,7 +60,6 @@ import java.util.concurrent.CompletableFuture;
|
||||||
public class GeyserModWorldManager extends GeyserWorldManager {
|
public class GeyserModWorldManager extends GeyserWorldManager {
|
||||||
|
|
||||||
private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();
|
private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();
|
||||||
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
|
|
||||||
private final MinecraftServer server;
|
private final MinecraftServer server;
|
||||||
|
|
||||||
public GeyserModWorldManager(MinecraftServer server) {
|
public GeyserModWorldManager(MinecraftServer server) {
|
||||||
|
|
@ -121,94 +107,6 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
||||||
return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion();
|
return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldExpectLecternHandled(GeyserSession session) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
|
|
||||||
server.execute(() -> {
|
|
||||||
ServerPlayer player = getPlayer(session);
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection resource - level() is just a getter
|
|
||||||
LevelChunk chunk = player.level().getChunk(x, z);
|
|
||||||
final int chunkBlockX = x << 4;
|
|
||||||
final int chunkBlockZ = z << 4;
|
|
||||||
//noinspection ForLoopReplaceableByForEach - avoid constructing iterator
|
|
||||||
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
|
||||||
BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i);
|
|
||||||
BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(),
|
|
||||||
blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ()));
|
|
||||||
sendLecternData(session, blockEntity, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendLecternData(GeyserSession session, int x, int y, int z) {
|
|
||||||
server.execute(() -> {
|
|
||||||
ServerPlayer player = getPlayer(session);
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//noinspection resource - level() is just a getter
|
|
||||||
BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(x, y, z));
|
|
||||||
sendLecternData(session, blockEntity, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) {
|
|
||||||
if (!(blockEntity instanceof LecternBlockEntity lectern)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x = blockEntity.getBlockPos().getX();
|
|
||||||
int y = blockEntity.getBlockPos().getY();
|
|
||||||
int z = blockEntity.getBlockPos().getZ();
|
|
||||||
|
|
||||||
if (!lectern.hasBook()) {
|
|
||||||
if (!isChunkLoad) {
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack book = lectern.getBook();
|
|
||||||
int pageCount = getPageCount(book);
|
|
||||||
boolean hasBookPages = pageCount > 0;
|
|
||||||
NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
|
|
||||||
lecternTag.putInt("page", lectern.getPage() / 2);
|
|
||||||
NbtMapBuilder bookTag = NbtMap.builder()
|
|
||||||
.putByte("Count", (byte) book.getCount())
|
|
||||||
.putShort("Damage", (short) 0)
|
|
||||||
.putString("Name", "minecraft:writable_book");
|
|
||||||
List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1);
|
|
||||||
if (hasBookPages) {
|
|
||||||
List<String> bookPages = getPages(book);
|
|
||||||
for (String page : bookPages) {
|
|
||||||
NbtMapBuilder pageBuilder = NbtMap.builder()
|
|
||||||
.putString("photoname", "")
|
|
||||||
.putString("text", page);
|
|
||||||
pages.add(pageBuilder.build());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Empty page
|
|
||||||
NbtMapBuilder pageBuilder = NbtMap.builder()
|
|
||||||
.putString("photoname", "")
|
|
||||||
.putString("text", "");
|
|
||||||
pages.add(pageBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
|
|
||||||
lecternTag.putCompound("book", bookTag.build());
|
|
||||||
NbtMap blockEntityTag = lecternTag.build();
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(GeyserSession session, String permission) {
|
public boolean hasPermission(GeyserSession session, String permission) {
|
||||||
ServerPlayer player = getPlayer(session);
|
ServerPlayer player = getPlayer(session);
|
||||||
|
|
@ -267,39 +165,6 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
||||||
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getPageCount(ItemStack itemStack) {
|
|
||||||
WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT);
|
|
||||||
if (writtenBookContent != null) {
|
|
||||||
return writtenBookContent.pages().size();
|
|
||||||
} else {
|
|
||||||
WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT);
|
|
||||||
return writableBookContent != null ? writableBookContent.pages().size() : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getPages(ItemStack itemStack) {
|
|
||||||
WrittenBookContent writtenBookContent = itemStack.get(DataComponents.WRITTEN_BOOK_CONTENT);
|
|
||||||
if (writtenBookContent != null) {
|
|
||||||
return writtenBookContent.pages().stream()
|
|
||||||
.map(Filterable::raw)
|
|
||||||
.map(GeyserModWorldManager::fromComponent)
|
|
||||||
.toList();
|
|
||||||
} else {
|
|
||||||
WritableBookContent writableBookContent = itemStack.get(DataComponents.WRITABLE_BOOK_CONTENT);
|
|
||||||
if (writableBookContent == null) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
return writableBookContent.pages().stream()
|
|
||||||
.map(Filterable::raw)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String fromComponent(Component component) {
|
|
||||||
String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY);
|
|
||||||
return LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static net.kyori.adventure.text.Component toKyoriComponent(Component component) {
|
private static net.kyori.adventure.text.Component toKyoriComponent(Component component) {
|
||||||
String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY);
|
String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY);
|
||||||
return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty());
|
return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty());
|
||||||
|
|
@ -309,7 +174,7 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
||||||
return patternLayers.layers().stream()
|
return patternLayers.layers().stream()
|
||||||
.map(layer -> {
|
.map(layer -> {
|
||||||
BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern(
|
BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern(
|
||||||
layer.pattern().value().assetId().toString(), layer.pattern().value().translationKey()
|
MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey()
|
||||||
);
|
);
|
||||||
return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId());
|
return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId());
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@ dependencies {
|
||||||
isTransitive = false
|
isTransitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implementation(libs.erosion.bukkit.nms) {
|
||||||
|
attributes {
|
||||||
|
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
implementation(variantOf(libs.adapters.spigot) {
|
implementation(variantOf(libs.adapters.spigot) {
|
||||||
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
|
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
|
||||||
})
|
})
|
||||||
|
|
@ -70,3 +76,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
exclude(dependency("com.mojang:.*"))
|
exclude(dependency("com.mojang:.*"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modrinth {
|
||||||
|
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||||
|
loaders.addAll("spigot", "paper")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ import java.util.logging.Logger;
|
||||||
public final class GeyserPaperLogger extends GeyserSpigotLogger {
|
public final class GeyserPaperLogger extends GeyserSpigotLogger {
|
||||||
private final ComponentLogger componentLogger;
|
private final ComponentLogger componentLogger;
|
||||||
|
|
||||||
public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) {
|
public GeyserPaperLogger(Plugin plugin, Logger logger) {
|
||||||
super(logger, debug);
|
super(logger);
|
||||||
componentLogger = plugin.getComponentLogger();
|
componentLogger = plugin.getComponentLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,15 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.spigot;
|
package org.geysermc.geyser.platform.spigot;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GeyserSpigotLogger implements GeyserLogger {
|
public class GeyserSpigotLogger implements GeyserLogger {
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,14 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserSpigotCommandManager geyserCommandManager;
|
private GeyserSpigotCommandManager geyserCommandManager;
|
||||||
private GeyserSpigotConfiguration geyserConfig;
|
private GeyserSpigotConfiguration geyserConfig;
|
||||||
private GeyserSpigotInjector geyserInjector;
|
private GeyserSpigotInjector geyserInjector;
|
||||||
private GeyserSpigotLogger geyserLogger;
|
private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ?
|
||||||
|
new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger());
|
||||||
private IGeyserPingPassthrough geyserSpigotPingPassthrough;
|
private IGeyserPingPassthrough geyserSpigotPingPassthrough;
|
||||||
private GeyserSpigotWorldManager geyserWorldManager;
|
private GeyserSpigotWorldManager geyserWorldManager;
|
||||||
|
|
||||||
|
|
@ -114,12 +114,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
// We depend on this as a fallback in certain scenarios
|
// We depend on this as a fallback in certain scenarios
|
||||||
BlockData.class.getMethod("getAsString");
|
BlockData.class.getMethod("getAsString");
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -128,12 +128,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
|
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
|
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -142,11 +142,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
try {
|
try {
|
||||||
Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator");
|
Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator");
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
|
geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
|
||||||
getLogger().severe("");
|
geyserLogger.error("");
|
||||||
getLogger().severe("*********************************************");
|
geyserLogger.error("*********************************************");
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -154,8 +154,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
if (!loadConfig()) {
|
if (!loadConfig()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode())
|
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||||
: new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
// Turn "(MC: 1.16.4)" into 1.16.4.
|
// Turn "(MC: 1.16.4)" into 1.16.4.
|
||||||
|
|
@ -252,6 +251,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||||
geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion);
|
geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion);
|
||||||
} catch (Exception e) { // Likely running on Paper 1.20.5+
|
} catch (Exception e) { // Likely running on Paper 1.20.5+
|
||||||
|
geyserLogger.debug("Unable to find spigot world manager: " + e.getMessage());
|
||||||
//noinspection deprecation
|
//noinspection deprecation
|
||||||
int protocolVersion = Bukkit.getUnsafe().getProtocolVersion();
|
int protocolVersion = Bukkit.getUnsafe().getProtocolVersion();
|
||||||
PaperAdapters.registerClosestWorldAdapter(protocolVersion);
|
PaperAdapters.registerClosestWorldAdapter(protocolVersion);
|
||||||
|
|
@ -266,7 +266,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper);
|
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper);
|
||||||
}
|
}
|
||||||
geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
|
geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) {
|
||||||
if (geyserConfig.isDebugMode()) {
|
if (geyserConfig.isDebugMode()) {
|
||||||
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
|
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
@ -486,7 +486,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,8 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.spigot.world;
|
package org.geysermc.geyser.platform.spigot.world;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
@ -40,13 +38,17 @@ import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockPistonEvent;
|
import org.bukkit.event.block.BlockPistonEvent;
|
||||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.block.property.Properties;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.level.physics.Direction;
|
import org.geysermc.geyser.level.physics.Direction;
|
||||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.PistonCache;
|
import org.geysermc.geyser.session.cache.PistonCache;
|
||||||
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -85,7 +87,7 @@ public class GeyserPistonListener implements Listener {
|
||||||
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
|
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
|
||||||
boolean sticky = event.isSticky();
|
boolean sticky = event.isSticky();
|
||||||
|
|
||||||
Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>();
|
Object2ObjectMap<Vector3i, BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
|
||||||
boolean blocksFilled = false;
|
boolean blocksFilled = false;
|
||||||
|
|
||||||
for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
|
for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
|
||||||
|
|
@ -108,10 +110,10 @@ public class GeyserPistonListener implements Listener {
|
||||||
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
||||||
for (Block block : blocks) {
|
for (Block block : blocks) {
|
||||||
Location attachedLocation = block.getLocation();
|
Location attachedLocation = block.getLocation();
|
||||||
int blockId = worldManager.getBlockNetworkId(block);
|
BlockState state = BlockState.of(worldManager.getBlockNetworkId(block));
|
||||||
// Ignore blocks that will be destroyed
|
// Ignore blocks that will be destroyed
|
||||||
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
|
if (BlockStateValues.canPistonMoveBlock(state, isExtend)) {
|
||||||
attachedBlocks.put(getVector(attachedLocation), blockId);
|
attachedBlocks.put(getVector(attachedLocation), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocksFilled = true;
|
blocksFilled = true;
|
||||||
|
|
@ -119,7 +121,7 @@ public class GeyserPistonListener implements Listener {
|
||||||
|
|
||||||
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
|
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
|
||||||
// event.getDirection() is unreliable
|
// event.getDirection() is unreliable
|
||||||
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
|
Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING);
|
||||||
|
|
||||||
session.executeInEventLoop(() -> {
|
session.executeInEventLoop(() -> {
|
||||||
PistonCache pistonCache = session.getPistonCache();
|
PistonCache pistonCache = session.getPistonCache();
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
@ -59,11 +59,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
|
||||||
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
||||||
} else {
|
} else {
|
||||||
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
||||||
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
|
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
|
||||||
}
|
}
|
||||||
placeBlockSoundPacket.setIdentifier(":");
|
placeBlockSoundPacket.setIdentifier(":");
|
||||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||||
session.setLastBlockPlacePosition(null);
|
session.setLastBlockPlacePosition(null);
|
||||||
session.setLastBlockPlacedId(null);
|
session.setLastBlockPlaced(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import org.geysermc.geyser.adapters.WorldAdapter;
|
||||||
import org.geysermc.geyser.adapters.paper.PaperAdapters;
|
import org.geysermc.geyser.adapters.paper.PaperAdapters;
|
||||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||||
|
|
@ -52,7 +53,7 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
return Block.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,30 +25,24 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.spigot.world.manager;
|
package org.geysermc.geyser.platform.spigot.world.manager;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.geysermc.erosion.bukkit.PickBlockUtils;
|
||||||
import org.geysermc.erosion.bukkit.BukkitLecterns;
|
|
||||||
import org.geysermc.erosion.bukkit.BukkitUtils;
|
|
||||||
import org.geysermc.erosion.bukkit.SchedulerUtils;
|
import org.geysermc.erosion.bukkit.SchedulerUtils;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.level.GameRule;
|
import org.geysermc.geyser.level.GameRule;
|
||||||
import org.geysermc.geyser.level.WorldManager;
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
|
@ -57,23 +51,21 @@ import java.util.concurrent.CompletableFuture;
|
||||||
*/
|
*/
|
||||||
public class GeyserSpigotWorldManager extends WorldManager {
|
public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final BukkitLecterns lecterns;
|
|
||||||
|
|
||||||
public GeyserSpigotWorldManager(Plugin plugin) {
|
public GeyserSpigotWorldManager(Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.lecterns = new BukkitLecterns(plugin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||||
Player bukkitPlayer;
|
Player bukkitPlayer;
|
||||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
World world = bukkitPlayer.getWorld();
|
World world = bukkitPlayer.getWorld();
|
||||||
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
|
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
|
||||||
// If the chunk isn't loaded, how could we even be here?
|
// If the chunk isn't loaded, how could we even be here?
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBlockNetworkId(world.getBlockAt(x, y, z));
|
return getBlockNetworkId(world.getBlockAt(x, y, z));
|
||||||
|
|
@ -84,9 +76,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
|
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
|
||||||
CompletableFuture<String> blockData = new CompletableFuture<>();
|
CompletableFuture<String> blockData = new CompletableFuture<>();
|
||||||
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
|
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
|
||||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
|
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
|
||||||
}
|
}
|
||||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -94,69 +86,6 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendLecternData(GeyserSession session, int x, int y, int z) {
|
|
||||||
Player bukkitPlayer;
|
|
||||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
|
|
||||||
// Run as a task to prevent async issues
|
|
||||||
SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
|
|
||||||
Player bukkitPlayer;
|
|
||||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (SchedulerUtils.FOLIA) {
|
|
||||||
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
|
|
||||||
if (chunk == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () ->
|
|
||||||
sendLecternData(session, chunk, blockEntityInfos));
|
|
||||||
} else {
|
|
||||||
Bukkit.getScheduler().runTask(this.plugin, () -> {
|
|
||||||
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
|
|
||||||
if (chunk == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendLecternData(session, chunk, blockEntityInfos);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private @Nullable Chunk getChunk(World world, int x, int z) {
|
|
||||||
if (!world.isChunkLoaded(x, z)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return world.getChunkAt(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendLecternData(GeyserSession session, Chunk chunk, List<BlockEntityInfo> blockEntityInfos) {
|
|
||||||
//noinspection ForLoopReplaceableByForEach - avoid constructing Iterator
|
|
||||||
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
|
||||||
BlockEntityInfo info = blockEntityInfos.get(i);
|
|
||||||
Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ());
|
|
||||||
sendLecternData(session, block, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) {
|
|
||||||
NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad);
|
|
||||||
if (blockEntityTag != null) {
|
|
||||||
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldExpectLecternHandled(GeyserSession session) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
||||||
org.bukkit.GameRule<?> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID());
|
org.bukkit.GameRule<?> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID());
|
||||||
if (bukkitGameRule == null) {
|
if (bukkitGameRule == null) {
|
||||||
|
|
@ -205,17 +134,16 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||||
CompletableFuture<@Nullable DataComponents> future = new CompletableFuture<>();
|
|
||||||
Player bukkitPlayer;
|
Player bukkitPlayer;
|
||||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
|
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
|
||||||
future.complete(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
return future;
|
|
||||||
}
|
}
|
||||||
|
CompletableFuture<Int2ObjectMap<byte[]>> future = new CompletableFuture<>();
|
||||||
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
|
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
|
||||||
// Paper 1.19.3 complains about async access otherwise.
|
// Paper 1.19.3 complains about async access otherwise.
|
||||||
// java.lang.IllegalStateException: Tile is null, asynchronous access?
|
// java.lang.IllegalStateException: Tile is null, asynchronous access?
|
||||||
SchedulerUtils.runTask(this.plugin, () -> future.complete(/*PickBlockUtils.pickBlock(block)*/ null), block); // TODO fix erosion once clear how to handle this
|
SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
|
||||||
return future;
|
return future.thenApply(RAW_TRANSFORMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserStandaloneConfiguration geyserConfig;
|
private GeyserStandaloneConfiguration geyserConfig;
|
||||||
private GeyserStandaloneLogger geyserLogger;
|
private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
|
||||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
private GeyserStandaloneGUI gui;
|
private GeyserStandaloneGUI gui;
|
||||||
@Getter
|
@Getter
|
||||||
|
|
@ -181,8 +181,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserStandaloneLogger();
|
|
||||||
|
|
||||||
if (useGui && gui == null) {
|
if (useGui && gui == null) {
|
||||||
gui = new GeyserStandaloneGUI(geyserLogger);
|
gui = new GeyserStandaloneGUI(geyserLogger);
|
||||||
gui.redirectSystemStreams();
|
gui.redirectSystemStreams();
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,9 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
|
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
|
||||||
exclude(dependency("net.kyori:adventure-nbt:.*"))
|
exclude(dependency("net.kyori:adventure-nbt:.*"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modrinth {
|
||||||
|
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||||
|
loaders.addAll("velocity")
|
||||||
}
|
}
|
||||||
|
|
@ -25,13 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.velocity;
|
package org.geysermc.geyser.platform.velocity;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GeyserVelocityLogger implements GeyserLogger {
|
public class GeyserVelocityLogger implements GeyserLogger {
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
|
|
|
||||||
|
|
@ -64,44 +64,44 @@ import java.util.UUID;
|
||||||
|
|
||||||
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||||
public class GeyserVelocityPlugin implements GeyserBootstrap {
|
public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
@Inject
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ProxyServer proxyServer;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private CommandManager commandManager;
|
|
||||||
|
|
||||||
|
private final ProxyServer proxyServer;
|
||||||
|
private final CommandManager commandManager;
|
||||||
|
private final GeyserVelocityLogger geyserLogger;
|
||||||
private GeyserCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserVelocityConfiguration geyserConfig;
|
private GeyserVelocityConfiguration geyserConfig;
|
||||||
private GeyserVelocityInjector geyserInjector;
|
private GeyserVelocityInjector geyserInjector;
|
||||||
private GeyserVelocityLogger geyserLogger;
|
|
||||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
|
|
||||||
private GeyserImpl geyser;
|
private GeyserImpl geyser;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
|
private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) {
|
||||||
|
this.geyserLogger = new GeyserVelocityLogger(logger);
|
||||||
|
this.proxyServer = server;
|
||||||
|
this.commandManager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGeyserInitialize() {
|
public void onGeyserInitialize() {
|
||||||
GeyserLocale.init(this);
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) {
|
if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) {
|
||||||
logger.error(" / \\");
|
geyserLogger.error(" / \\");
|
||||||
logger.error(" / \\");
|
geyserLogger.error(" / \\");
|
||||||
logger.error(" / | \\");
|
geyserLogger.error(" / | \\");
|
||||||
logger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
|
geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
|
||||||
logger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||||
logger.error(" / o \\");
|
geyserLogger.error(" / o \\");
|
||||||
logger.error("/_____________\\");
|
geyserLogger.error("/_____________\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loadConfig()) {
|
if (!loadConfig()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
|
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
|
||||||
|
|
@ -249,7 +249,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,23 @@ package org.geysermc.geyser.platform.viaproxy;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||||
import net.raphimc.viaproxy.ViaProxy;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
|
import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig;
|
||||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
|
||||||
public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
|
private RemoteConfiguration remote = new RemoteConfiguration() {
|
||||||
|
@Override
|
||||||
|
public boolean isForwardHost() {
|
||||||
|
return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyPath() {
|
public Path getFloodgateKeyPath() {
|
||||||
return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath();
|
return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath();
|
||||||
|
|
@ -50,4 +59,9 @@ public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
||||||
return interval;
|
return interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteConfiguration getRemote() {
|
||||||
|
return this.remote;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import org.apache.logging.log4j.LogManager;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.api.util.PlatformType;
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
|
|
@ -44,6 +45,7 @@ import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.geyser.platform.viaproxy.listener.GeyserServerTransferListener;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.util.FileUtils;
|
||||||
|
|
@ -57,7 +59,7 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap {
|
public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap, EventRegistrar {
|
||||||
|
|
||||||
public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
|
public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
|
||||||
|
|
||||||
|
|
@ -120,6 +122,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this);
|
this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this);
|
||||||
|
this.geyser.eventBus().register(this, new GeyserServerTransferListener());
|
||||||
LoopbackUtil.checkAndApplyLoopback(this.logger);
|
LoopbackUtil.checkAndApplyLoopback(this.logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.viaproxy.listener;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.net.HostAndPort;
|
||||||
|
import org.geysermc.event.PostOrder;
|
||||||
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
|
import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent;
|
||||||
|
import org.geysermc.geyser.api.event.java.ServerTransferEvent;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class GeyserServerTransferListener {
|
||||||
|
|
||||||
|
private final Cache<String, Map<String, byte[]>> cookieStorages = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||||
|
|
||||||
|
@Subscribe(postOrder = PostOrder.FIRST)
|
||||||
|
private void onServerTransfer(final ServerTransferEvent event) {
|
||||||
|
this.cookieStorages.put(event.connection().xuid(), event.cookies());
|
||||||
|
final GeyserSession geyserSession = (GeyserSession) event.connection();
|
||||||
|
final HostAndPort hostAndPort = HostAndPort.fromString(geyserSession.getClientData().getServerAddress()).withDefaultPort(19132);
|
||||||
|
event.bedrockHost(hostAndPort.getHost());
|
||||||
|
event.bedrockPort(hostAndPort.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(postOrder = PostOrder.FIRST)
|
||||||
|
private void onSessionLogin(final SessionLoginEvent event) {
|
||||||
|
final Map<String, byte[]> cookies = this.cookieStorages.asMap().remove(event.connection().xuid());
|
||||||
|
if (cookies != null) {
|
||||||
|
event.cookies(cookies);
|
||||||
|
event.transferring(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,9 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// this is OK as long as the same version catalog is used in the main build and build-logic
|
||||||
|
// see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
|
||||||
|
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
|
||||||
implementation(libs.indra)
|
implementation(libs.indra)
|
||||||
implementation(libs.shadow)
|
implementation(libs.shadow)
|
||||||
implementation(libs.architectury.plugin)
|
implementation(libs.architectury.plugin)
|
||||||
|
|
|
||||||
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
|
||||||
|
val Project.libs: LibrariesForLibs
|
||||||
|
get() = rootProject.extensions.getByType()
|
||||||
|
|
@ -8,7 +8,6 @@ plugins {
|
||||||
id("geyser.publish-conventions")
|
id("geyser.publish-conventions")
|
||||||
id("architectury-plugin")
|
id("architectury-plugin")
|
||||||
id("dev.architectury.loom")
|
id("dev.architectury.loom")
|
||||||
id("com.modrinth.minotaur")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are provided by Minecraft/modded platforms already, no need to include them
|
// These are provided by Minecraft/modded platforms already, no need to include them
|
||||||
|
|
@ -39,7 +38,7 @@ provided("io.netty", "netty-resolver-dns-native-macos")
|
||||||
provided("org.ow2.asm", "asm")
|
provided("org.ow2.asm", "asm")
|
||||||
|
|
||||||
architectury {
|
architectury {
|
||||||
minecraft = "1.20.5"
|
minecraft = libs.minecraft.get().version as String
|
||||||
}
|
}
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
|
|
@ -83,7 +82,7 @@ tasks {
|
||||||
register("remapModrinthJar", RemapJarTask::class) {
|
register("remapModrinthJar", RemapJarTask::class) {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
inputFile.set(shadowJar.get().archiveFile)
|
inputFile.set(shadowJar.get().archiveFile)
|
||||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
|
archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER"))
|
||||||
archiveClassifier.set("")
|
archiveClassifier.set("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +92,7 @@ afterEvaluate {
|
||||||
|
|
||||||
// These are shaded, no need to JiJ them
|
// These are shaded, no need to JiJ them
|
||||||
configurations["shadow"].dependencies.forEach {shadowed ->
|
configurations["shadow"].dependencies.forEach {shadowed ->
|
||||||
println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
|
//println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
|
||||||
providedDependencies.add("${shadowed.group}:${shadowed.name}")
|
providedDependencies.add("${shadowed.group}:${shadowed.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,39 +100,24 @@ afterEvaluate {
|
||||||
configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep ->
|
configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep ->
|
||||||
if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}")
|
if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}")
|
||||||
and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) {
|
and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) {
|
||||||
println("Including dependency via JiJ: ${dep.id}")
|
//println("Including dependency via JiJ: ${dep.id}")
|
||||||
dependencies.add("include", dep.moduleVersion.id.toString())
|
dependencies.add("include", dep.moduleVersion.id.toString())
|
||||||
} else {
|
} else {
|
||||||
println("Not including ${dep.id} for ${project.name}!")
|
//println("Not including ${dep.id} for ${project.name}!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft("com.mojang:minecraft:1.20.5")
|
minecraft(libs.minecraft)
|
||||||
mappings(loom.officialMojangMappings())
|
mappings(loom.officialMojangMappings())
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// mavenLocal()
|
// mavenLocal()
|
||||||
maven("https://repo.opencollab.dev/maven-releases/")
|
maven("https://repo.opencollab.dev/main")
|
||||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||||
maven("https://maven.neoforged.net/releases")
|
maven("https://maven.neoforged.net/releases")
|
||||||
}
|
|
||||||
|
|
||||||
modrinth {
|
|
||||||
token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
|
||||||
projectId.set("wKkoqHrH")
|
|
||||||
versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER"))
|
|
||||||
versionType.set("beta")
|
|
||||||
changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
|
|
||||||
|
|
||||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
|
||||||
|
|
||||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
|
||||||
gameVersions.addAll("1.20.5", "1.20.6")
|
|
||||||
failSilently.set(true)
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
plugins {
|
||||||
|
id("com.modrinth.minotaur")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the readme is synched
|
||||||
|
tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody)
|
||||||
|
|
||||||
|
modrinth {
|
||||||
|
token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||||
|
projectId.set("geyser")
|
||||||
|
versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER"))
|
||||||
|
versionType.set("beta")
|
||||||
|
changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
|
||||||
|
gameVersions.add(libs.minecraft.get().version as String)
|
||||||
|
failSilently.set(true)
|
||||||
|
|
||||||
|
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,14 @@ val moddedPlatforms = setOf(
|
||||||
projects.mod
|
projects.mod
|
||||||
).map { it.dependencyProject }
|
).map { it.dependencyProject }
|
||||||
|
|
||||||
|
val modrinthPlatforms = setOf(
|
||||||
|
projects.bungeecord,
|
||||||
|
projects.fabric,
|
||||||
|
projects.neoforge,
|
||||||
|
projects.spigot,
|
||||||
|
projects.velocity
|
||||||
|
).map { it.dependencyProject }
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply {
|
apply {
|
||||||
plugin("java-library")
|
plugin("java-library")
|
||||||
|
|
@ -38,4 +46,10 @@ subprojects {
|
||||||
in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
|
in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
|
||||||
else -> plugins.apply("geyser.base-conventions")
|
else -> plugins.apply("geyser.base-conventions")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not combined with platform-conventions as that also contains
|
||||||
|
// platforms which we cant publish to modrinth
|
||||||
|
if (modrinthPlatforms.contains(this)) {
|
||||||
|
plugins.apply("geyser.modrinth-uploading-conventions")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +24,6 @@ dependencies {
|
||||||
implementation(libs.websocket)
|
implementation(libs.websocket)
|
||||||
|
|
||||||
api(libs.bundles.protocol)
|
api(libs.bundles.protocol)
|
||||||
implementation(libs.blockstateupdater)
|
|
||||||
|
|
||||||
api(libs.mcauthlib)
|
api(libs.mcauthlib)
|
||||||
api(libs.mcprotocollib) {
|
api(libs.mcprotocollib) {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
import org.geysermc.cumulus.form.Form;
|
import org.geysermc.cumulus.form.Form;
|
||||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
|
import org.geysermc.erosion.packet.Packets;
|
||||||
import org.geysermc.floodgate.crypto.AesCipher;
|
import org.geysermc.floodgate.crypto.AesCipher;
|
||||||
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
||||||
import org.geysermc.floodgate.crypto.Base64Topping;
|
import org.geysermc.floodgate.crypto.Base64Topping;
|
||||||
|
|
@ -77,6 +78,7 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
|
import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
|
||||||
import org.geysermc.geyser.session.SessionManager;
|
import org.geysermc.geyser.session.SessionManager;
|
||||||
|
import org.geysermc.geyser.session.cache.RegistryCache;
|
||||||
import org.geysermc.geyser.skin.FloodgateSkinUploader;
|
import org.geysermc.geyser.skin.FloodgateSkinUploader;
|
||||||
import org.geysermc.geyser.skin.ProvidedSkins;
|
import org.geysermc.geyser.skin.ProvidedSkins;
|
||||||
import org.geysermc.geyser.skin.SkinProvider;
|
import org.geysermc.geyser.skin.SkinProvider;
|
||||||
|
|
@ -211,6 +213,8 @@ public class GeyserImpl implements GeyserApi {
|
||||||
Registries.init();
|
Registries.init();
|
||||||
BlockRegistries.init();
|
BlockRegistries.init();
|
||||||
|
|
||||||
|
RegistryCache.init();
|
||||||
|
|
||||||
/* Initialize translators */
|
/* Initialize translators */
|
||||||
EntityDefinitions.init();
|
EntityDefinitions.init();
|
||||||
MessageTranslator.init();
|
MessageTranslator.init();
|
||||||
|
|
@ -383,7 +387,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
|
|
||||||
this.newsHandler = new NewsHandler(BRANCH, this.buildNumber());
|
this.newsHandler = new NewsHandler(BRANCH, this.buildNumber());
|
||||||
|
|
||||||
//Packets.initGeyser();
|
Packets.initGeyser();
|
||||||
|
|
||||||
if (Epoll.isAvailable()) {
|
if (Epoll.isAvailable()) {
|
||||||
this.erosionUnixListener = new UnixSocketClientListener();
|
this.erosionUnixListener = new UnixSocketClientListener();
|
||||||
|
|
@ -766,6 +770,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection DataFlowIssue
|
||||||
return Integer.parseInt(BUILD_NUMBER);
|
return Integer.parseInt(BUILD_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
private boolean debugMode = false;
|
private boolean debugMode = false;
|
||||||
|
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes = true;
|
private boolean allowThirdPartyCapes = false;
|
||||||
|
|
||||||
@JsonProperty("show-cooldown")
|
@JsonProperty("show-cooldown")
|
||||||
private String showCooldown = "title";
|
private String showCooldown = "title";
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.entity;
|
package org.geysermc.geyser.entity;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.entity.type.AbstractWindChargeEntity;
|
||||||
|
import org.geysermc.geyser.entity.factory.EntityFactory;
|
||||||
import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
|
import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
|
@ -63,6 +65,9 @@ public final class EntityDefinitions {
|
||||||
public static final EntityDefinition<BeeEntity> BEE;
|
public static final EntityDefinition<BeeEntity> BEE;
|
||||||
public static final EntityDefinition<BlazeEntity> BLAZE;
|
public static final EntityDefinition<BlazeEntity> BLAZE;
|
||||||
public static final EntityDefinition<BoatEntity> BOAT;
|
public static final EntityDefinition<BoatEntity> BOAT;
|
||||||
|
public static final EntityDefinition<BoggedEntity> BOGGED;
|
||||||
|
public static final EntityDefinition<BreezeEntity> BREEZE;
|
||||||
|
public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE;
|
||||||
public static final EntityDefinition<CamelEntity> CAMEL;
|
public static final EntityDefinition<CamelEntity> CAMEL;
|
||||||
public static final EntityDefinition<CatEntity> CAT;
|
public static final EntityDefinition<CatEntity> CAT;
|
||||||
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
|
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
|
||||||
|
|
@ -165,6 +170,7 @@ public final class EntityDefinitions {
|
||||||
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
|
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
|
||||||
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
|
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
|
||||||
public static final EntityDefinition<WardenEntity> WARDEN;
|
public static final EntityDefinition<WardenEntity> WARDEN;
|
||||||
|
public static final EntityDefinition<AbstractWindChargeEntity> WIND_CHARGE;
|
||||||
public static final EntityDefinition<RaidParticipantEntity> WITCH;
|
public static final EntityDefinition<RaidParticipantEntity> WITCH;
|
||||||
public static final EntityDefinition<WitherEntity> WITHER;
|
public static final EntityDefinition<WitherEntity> WITHER;
|
||||||
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
|
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
|
||||||
|
|
@ -375,6 +381,18 @@ public final class EntityDefinitions {
|
||||||
.heightAndWidth(0.25f)
|
.heightAndWidth(0.25f)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
EntityFactory<AbstractWindChargeEntity> windChargeSupplier = AbstractWindChargeEntity::new;
|
||||||
|
BREEZE_WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||||
|
.type(EntityType.BREEZE_WIND_CHARGE)
|
||||||
|
.identifier("minecraft:breeze_wind_charge_projectile")
|
||||||
|
.heightAndWidth(0.3125f)
|
||||||
|
.build();
|
||||||
|
WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||||
|
.type(EntityType.WIND_CHARGE)
|
||||||
|
.identifier("minecraft:wind_charge_projectile")
|
||||||
|
.heightAndWidth(0.3125f)
|
||||||
|
.build();
|
||||||
|
|
||||||
EntityDefinition<AbstractArrowEntity> abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
|
EntityDefinition<AbstractArrowEntity> abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
|
||||||
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
|
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
|
||||||
.addTranslator(null) // "Piercing level"
|
.addTranslator(null) // "Piercing level"
|
||||||
|
|
@ -503,11 +521,20 @@ public final class EntityDefinitions {
|
||||||
.height(0.9f).width(0.5f)
|
.height(0.9f).width(0.5f)
|
||||||
.addTranslator(MetadataType.BYTE, BatEntity::setBatFlags)
|
.addTranslator(MetadataType.BYTE, BatEntity::setBatFlags)
|
||||||
.build();
|
.build();
|
||||||
|
BOGGED = EntityDefinition.inherited(BoggedEntity::new, mobEntityBase)
|
||||||
|
.type(EntityType.BOGGED)
|
||||||
|
.height(1.99f).width(0.6f)
|
||||||
|
.addTranslator(MetadataType.BOOLEAN, BoggedEntity::setSheared)
|
||||||
|
.build();
|
||||||
BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase)
|
BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase)
|
||||||
.type(EntityType.BLAZE)
|
.type(EntityType.BLAZE)
|
||||||
.height(1.8f).width(0.6f)
|
.height(1.8f).width(0.6f)
|
||||||
.addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags)
|
.addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags)
|
||||||
.build();
|
.build();
|
||||||
|
BREEZE = EntityDefinition.inherited(BreezeEntity::new, mobEntityBase)
|
||||||
|
.type(EntityType.BREEZE)
|
||||||
|
.height(1.77f).width(0.6f)
|
||||||
|
.build();
|
||||||
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
|
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
|
||||||
.type(EntityType.CREEPER)
|
.type(EntityType.CREEPER)
|
||||||
.height(1.7f).width(0.6f)
|
.height(1.7f).width(0.6f)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.entity.type;
|
||||||
|
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that, as of 1.21, a wind charge entity does not actually implement the thrown item. We're just reusing
|
||||||
|
* the "hide until far away" aspect.
|
||||||
|
*/
|
||||||
|
public class AbstractWindChargeEntity extends ThrowableItemEntity {
|
||||||
|
public AbstractWindChargeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float getDrag() {
|
||||||
|
// Always, even in water. As of 1.21.
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
|
import org.geysermc.geyser.inventory.item.Potion;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||||
|
|
||||||
|
|
@ -46,12 +46,7 @@ public class ArrowEntity extends AbstractArrowEntity {
|
||||||
if (potionColor == -1) {
|
if (potionColor == -1) {
|
||||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
|
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
|
||||||
} else {
|
} else {
|
||||||
TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor);
|
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, Potion.toTippedArrowId(potionColor));
|
||||||
if (potion != null && potion.getJavaColor() != -1) {
|
|
||||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) potion.getBedrockId());
|
|
||||||
} else {
|
|
||||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BoatEntity extends Entity implements Tickable {
|
public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
|
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
|
||||||
|
|
@ -65,6 +65,8 @@ public class BoatEntity extends Entity implements Tickable {
|
||||||
@Getter
|
@Getter
|
||||||
private int variant;
|
private int variant;
|
||||||
|
|
||||||
|
private long leashHolderBedrockId = -1;
|
||||||
|
|
||||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||||
private final float ROWING_SPEED = 0.1f;
|
private final float ROWING_SPEED = 0.1f;
|
||||||
|
|
||||||
|
|
@ -147,8 +149,18 @@ public class BoatEntity extends Entity implements Tickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLeashHolderBedrockId(long bedrockId) {
|
||||||
|
this.leashHolderBedrockId = bedrockId;
|
||||||
|
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InteractiveTag testInteraction(Hand hand) {
|
protected InteractiveTag testInteraction(Hand hand) {
|
||||||
|
InteractiveTag tag = super.testInteraction(hand);
|
||||||
|
if (tag != InteractiveTag.NONE) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
if (session.isSneaking()) {
|
if (session.isSneaking()) {
|
||||||
return InteractiveTag.NONE;
|
return InteractiveTag.NONE;
|
||||||
} else if (passengers.size() < 2) {
|
} else if (passengers.size() < 2) {
|
||||||
|
|
@ -160,6 +172,10 @@ public class BoatEntity extends Entity implements Tickable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionResult interact(Hand hand) {
|
public InteractionResult interact(Hand hand) {
|
||||||
|
InteractionResult result = super.interact(hand);
|
||||||
|
if (result != InteractionResult.PASS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
if (session.isSneaking()) {
|
if (session.isSneaking()) {
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -191,6 +207,11 @@ public class BoatEntity extends Entity implements Tickable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long leashHolderBedrockId() {
|
||||||
|
return leashHolderBedrockId;
|
||||||
|
}
|
||||||
|
|
||||||
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
||||||
AnimatePacket packet = new AnimatePacket();
|
AnimatePacket packet = new AnimatePacket();
|
||||||
packet.setRuntimeEntityId(rower.getGeyserId());
|
packet.setRuntimeEntityId(rower.getGeyserId());
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
|
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
|
||||||
import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager;
|
import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager;
|
||||||
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
import org.geysermc.geyser.util.EntityUtils;
|
import org.geysermc.geyser.util.EntityUtils;
|
||||||
|
|
@ -137,7 +138,7 @@ public class Entity implements GeyserEntity {
|
||||||
|
|
||||||
this.valid = false;
|
this.valid = false;
|
||||||
|
|
||||||
this.propertyManager = new GeyserEntityPropertyManager(definition.registeredProperties());
|
this.propertyManager = definition.registeredProperties() == null ? null : new GeyserEntityPropertyManager(definition.registeredProperties());
|
||||||
|
|
||||||
setPosition(position);
|
setPosition(position);
|
||||||
setAirSupply(getMaxAir());
|
setAirSupply(getMaxAir());
|
||||||
|
|
@ -364,7 +365,7 @@ public class Entity implements GeyserEntity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyManager.hasProperties()) {
|
if (propertyManager != null && propertyManager.hasProperties()) {
|
||||||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||||
entityDataPacket.setRuntimeEntityId(geyserId);
|
entityDataPacket.setRuntimeEntityId(geyserId);
|
||||||
propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties());
|
propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties());
|
||||||
|
|
@ -557,6 +558,17 @@ public class Entity implements GeyserEntity {
|
||||||
* Should usually mirror {@link #interact(Hand)} without any side effects.
|
* Should usually mirror {@link #interact(Hand)} without any side effects.
|
||||||
*/
|
*/
|
||||||
protected InteractiveTag testInteraction(Hand hand) {
|
protected InteractiveTag testInteraction(Hand hand) {
|
||||||
|
if (isAlive() && this instanceof Leashable leashable) {
|
||||||
|
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Note this might be client side. Has yet to be an issue though, as of Java 1.21.
|
||||||
|
return InteractiveTag.REMOVE_LEASH;
|
||||||
|
}
|
||||||
|
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
|
||||||
|
// We shall leash
|
||||||
|
return InteractiveTag.LEASH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return InteractiveTag.NONE;
|
return InteractiveTag.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,6 +577,18 @@ public class Entity implements GeyserEntity {
|
||||||
* to ensure packet parity as well as functionality parity (such as sound effect responses).
|
* to ensure packet parity as well as functionality parity (such as sound effect responses).
|
||||||
*/
|
*/
|
||||||
public InteractionResult interact(Hand hand) {
|
public InteractionResult interact(Hand hand) {
|
||||||
|
if (isAlive() && this instanceof Leashable leashable) {
|
||||||
|
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Note this might also update client side (a theoretical Geyser/client desync and Java parity issue).
|
||||||
|
// Has yet to be an issue though, as of Java 1.21.
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
|
||||||
|
// We shall leash
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import org.geysermc.erosion.util.BlockPositionIterator;
|
||||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.level.physics.BoundingBox;
|
import org.geysermc.geyser.level.physics.BoundingBox;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||||
|
|
@ -162,7 +163,7 @@ public class FishingHookEntity extends ThrowableEntity {
|
||||||
*/
|
*/
|
||||||
protected boolean isInAir() {
|
protected boolean isInAir() {
|
||||||
int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
|
int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
|
||||||
return block == BlockStateValues.JAVA_AIR_ID;
|
return block == Block.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,16 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.entity.type;
|
package org.geysermc.geyser.entity.type;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.Blocks;
|
||||||
|
import org.geysermc.geyser.level.block.property.Properties;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.InteractionResult;
|
import org.geysermc.geyser.util.InteractionResult;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -51,7 +53,8 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDefaultBlockMetadata() {
|
public void updateDefaultBlockMetadata() {
|
||||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID));
|
BlockState furnace = Blocks.FURNACE.defaultBlockState().withValue(Properties.LIT, hasFuel);
|
||||||
|
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(furnace));
|
||||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,10 @@ public class InteractionEntity extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(FloatEntityMetadata height) {
|
public void setHeight(FloatEntityMetadata height) {
|
||||||
setBoundingBoxHeight(height.getPrimitiveValue());
|
// Bedrock does *not* like high values being placed here
|
||||||
|
// https://gist.github.com/Owen1212055/f5d59169d3a6a5c32f0c173d57eb199d recommend(s/ed) using the tactic
|
||||||
|
// https://github.com/GeyserMC/Geyser/issues/4688
|
||||||
|
setBoundingBoxHeight(Math.min(height.getPrimitiveValue(), 64f));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResponse(BooleanEntityMetadata response) {
|
public void setResponse(BooleanEntityMetadata response) {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.packet.AddItemEntityPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
|
@ -137,7 +138,7 @@ public class ItemEntity extends ThrowableEntity {
|
||||||
protected float getDrag() {
|
protected float getDrag() {
|
||||||
if (isOnGround()) {
|
if (isOnGround()) {
|
||||||
Vector3i groundBlockPos = position.toInt().down(1);
|
Vector3i groundBlockPos = position.toInt().down(1);
|
||||||
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, groundBlockPos);
|
BlockState blockState = session.getGeyser().getWorldManager().blockAt(session, groundBlockPos);
|
||||||
return BlockStateValues.getSlipperiness(blockState) * 0.98f;
|
return BlockStateValues.getSlipperiness(blockState) * 0.98f;
|
||||||
}
|
}
|
||||||
return 0.98f;
|
return 0.98f;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
@ -23,12 +23,22 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.entity.type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains useful collections for use in Geyser.
|
* I can haz lead
|
||||||
* <p>
|
* (The item, not the mineral)
|
||||||
* Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be
|
|
||||||
* added that are not greater by one versus the previous key. Because of this, speedy operations of {@link java.util.Map#get(java.lang.Object)}
|
|
||||||
* and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map
|
|
||||||
* size and its "start" integer.
|
|
||||||
*/
|
*/
|
||||||
package org.geysermc.geyser.util.collection;
|
public interface Leashable {
|
||||||
|
void setLeashHolderBedrockId(long bedrockId);
|
||||||
|
|
||||||
|
long leashHolderBedrockId();
|
||||||
|
|
||||||
|
default boolean canBeLeashed() {
|
||||||
|
return isNotLeashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isNotLeashed() {
|
||||||
|
return leashHolderBedrockId() == -1L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.level.PaintingType;
|
import org.geysermc.geyser.level.PaintingType;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||||
|
|
||||||
|
|
@ -49,8 +51,14 @@ public class PaintingEntity extends Entity {
|
||||||
// Wait until we get the metadata needed
|
// Wait until we get the metadata needed
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaintingType(ObjectEntityMetadata<org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType> entityMetadata) {
|
public void setPaintingType(ObjectEntityMetadata<Holder<PaintingVariant>> entityMetadata) {
|
||||||
PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue());
|
if (!entityMetadata.getValue().isId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PaintingType type = session.getRegistryCache().paintings().byId(entityMetadata.getValue().id());
|
||||||
|
if (type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
|
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
|
||||||
addPaintingPacket.setUniqueEntityId(geyserId);
|
addPaintingPacket.setUniqueEntityId(geyserId);
|
||||||
addPaintingPacket.setRuntimeEntityId(geyserId);
|
addPaintingPacket.setRuntimeEntityId(geyserId);
|
||||||
|
|
@ -79,7 +87,7 @@ public class PaintingEntity extends Entity {
|
||||||
private Vector3f fixOffset(PaintingType paintingName) {
|
private Vector3f fixOffset(PaintingType paintingName) {
|
||||||
Vector3f position = super.position;
|
Vector3f position = super.position;
|
||||||
position = position.add(0.5, 0.5, 0.5);
|
position = position.add(0.5, 0.5, 0.5);
|
||||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0;
|
||||||
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||||
|
|
||||||
return switch (direction) {
|
return switch (direction) {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.Blocks;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDefaultBlockMetadata() {
|
public void updateDefaultBlockMetadata() {
|
||||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(BlockStateValues.JAVA_SPAWNER_ID));
|
dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(Blocks.SPAWNER.defaultBlockState()));
|
||||||
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public class AmbientEntity extends MobEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ public class DolphinEntity extends WaterEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,12 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.entity.type.living;
|
package org.geysermc.geyser.entity.type.living;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.entity.type.Leashable;
|
||||||
import org.geysermc.geyser.entity.type.LivingEntity;
|
import org.geysermc.geyser.entity.type.LivingEntity;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
|
|
@ -43,11 +43,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class MobEntity extends LivingEntity {
|
public class MobEntity extends LivingEntity implements Leashable {
|
||||||
/**
|
/**
|
||||||
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
|
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
|
||||||
*/
|
*/
|
||||||
@Getter
|
|
||||||
private long leashHolderBedrockId;
|
private long leashHolderBedrockId;
|
||||||
|
|
||||||
public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
|
@ -65,6 +64,7 @@ public class MobEntity extends LivingEntity {
|
||||||
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
|
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setLeashHolderBedrockId(long bedrockId) {
|
public void setLeashHolderBedrockId(long bedrockId) {
|
||||||
this.leashHolderBedrockId = bedrockId;
|
this.leashHolderBedrockId = bedrockId;
|
||||||
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
|
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
|
||||||
|
|
@ -79,10 +79,7 @@ public class MobEntity extends LivingEntity {
|
||||||
return InteractiveTag.REMOVE_LEASH;
|
return InteractiveTag.REMOVE_LEASH;
|
||||||
} else {
|
} else {
|
||||||
GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand);
|
GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand);
|
||||||
if (itemStack.asItem() == Items.LEAD && canBeLeashed()) {
|
if (itemStack.asItem() == Items.NAME_TAG) {
|
||||||
// We shall leash
|
|
||||||
return InteractiveTag.LEASH;
|
|
||||||
} else if (itemStack.asItem() == Items.NAME_TAG) {
|
|
||||||
InteractionResult result = checkInteractWithNameTag(itemStack);
|
InteractionResult result = checkInteractWithNameTag(itemStack);
|
||||||
if (result.consumesAction()) {
|
if (result.consumesAction()) {
|
||||||
return InteractiveTag.NAME;
|
return InteractiveTag.NAME;
|
||||||
|
|
@ -99,9 +96,6 @@ public class MobEntity extends LivingEntity {
|
||||||
if (!isAlive()) {
|
if (!isAlive()) {
|
||||||
// dead lol
|
// dead lol
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
} else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) {
|
|
||||||
// TODO looks like the client assumes it will go through and removes the attachment itself?
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
} else {
|
} else {
|
||||||
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand);
|
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand);
|
||||||
InteractionResult result = checkPriorityInteractions(itemInHand);
|
InteractionResult result = checkPriorityInteractions(itemInHand);
|
||||||
|
|
@ -115,10 +109,7 @@ public class MobEntity extends LivingEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) {
|
private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) {
|
||||||
if (itemInHand.asItem() == Items.LEAD && canBeLeashed()) {
|
if (itemInHand.asItem() == Items.NAME_TAG) {
|
||||||
// We shall leash
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
} else if (itemInHand.asItem() == Items.NAME_TAG) {
|
|
||||||
InteractionResult result = checkInteractWithNameTag(itemInHand);
|
InteractionResult result = checkInteractWithNameTag(itemInHand);
|
||||||
if (result.consumesAction()) {
|
if (result.consumesAction()) {
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -143,12 +134,14 @@ public class MobEntity extends LivingEntity {
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canBeLeashed() {
|
@Override
|
||||||
|
public boolean canBeLeashed() {
|
||||||
return isNotLeashed() && !isEnemy();
|
return isNotLeashed() && !isEnemy();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final boolean isNotLeashed() {
|
@Override
|
||||||
return leashHolderBedrockId == -1L;
|
public long leashHolderBedrockId() {
|
||||||
|
return leashHolderBedrockId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return isNotLeashed();
|
return isNotLeashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public class WaterEntity extends CreatureEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ public class AxolotlEntity extends AnimalEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public class HoglinEntity extends AnimalEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return isNotLeashed();
|
return isNotLeashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public class PandaEntity extends AnimalEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class TurtleEntity extends AnimalEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ public abstract class TameableEntity extends AnimalEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return isNotLeashed();
|
return isNotLeashed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,36 +33,28 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
|
import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
|
||||||
import org.geysermc.geyser.item.type.DyeItem;
|
import org.geysermc.geyser.item.type.DyeItem;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||||
import org.geysermc.geyser.util.InteractionResult;
|
import org.geysermc.geyser.util.InteractionResult;
|
||||||
import org.geysermc.geyser.util.InteractiveTag;
|
import org.geysermc.geyser.util.InteractiveTag;
|
||||||
import org.geysermc.geyser.util.ItemUtils;
|
import org.geysermc.geyser.util.ItemUtils;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class WolfEntity extends TameableEntity {
|
public class WolfEntity extends TameableEntity {
|
||||||
/**
|
|
||||||
* A list of all foods a wolf can eat on Java Edition.
|
|
||||||
* Used to display interactive tag or particles if needed.
|
|
||||||
* TODO generate
|
|
||||||
*/
|
|
||||||
private static final Set<Item> WOLF_FOODS = Set.of(Items.PUFFERFISH, Items.TROPICAL_FISH, Items.CHICKEN, Items.COOKED_CHICKEN,
|
|
||||||
Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
|
|
||||||
Items.COOKED_RABBIT);
|
|
||||||
|
|
||||||
private byte collarColor = 14; // Red - default
|
private byte collarColor = 14; // Red - default
|
||||||
|
|
||||||
private boolean isCurseOfBinding = false;
|
private boolean isCurseOfBinding = false;
|
||||||
|
|
@ -112,12 +104,14 @@ public class WolfEntity extends TameableEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.20.5+
|
// 1.20.5+
|
||||||
public void setWolfVariant(IntEntityMetadata entityMetadata) {
|
public void setWolfVariant(ObjectEntityMetadata<Holder<WolfVariant>> entityMetadata) {
|
||||||
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue());
|
entityMetadata.getValue().ifId(id -> {
|
||||||
if (wolfVariant == null) {
|
BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id);
|
||||||
wolfVariant = WolfVariant.PALE;
|
if (wolfVariant == null) {
|
||||||
}
|
wolfVariant = BuiltInWolfVariant.PALE;
|
||||||
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
|
}
|
||||||
|
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -129,11 +123,11 @@ public class WolfEntity extends TameableEntity {
|
||||||
@Override
|
@Override
|
||||||
public void setChestplate(ItemStack stack) {
|
public void setChestplate(ItemStack stack) {
|
||||||
super.setChestplate(stack);
|
super.setChestplate(stack);
|
||||||
isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0;
|
isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
|
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,7 +181,7 @@ public class WolfEntity extends TameableEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ordered by bedrock id
|
// Ordered by bedrock id
|
||||||
public enum WolfVariant {
|
public enum BuiltInWolfVariant {
|
||||||
PALE,
|
PALE,
|
||||||
ASHEN,
|
ASHEN,
|
||||||
BLACK,
|
BLACK,
|
||||||
|
|
@ -198,16 +192,16 @@ public class WolfEntity extends TameableEntity {
|
||||||
STRIPED,
|
STRIPED,
|
||||||
WOODS;
|
WOODS;
|
||||||
|
|
||||||
private static final WolfVariant[] VALUES = values();
|
private static final BuiltInWolfVariant[] VALUES = values();
|
||||||
|
|
||||||
private final String javaIdentifier;
|
private final String javaIdentifier;
|
||||||
|
|
||||||
WolfVariant() {
|
BuiltInWolfVariant() {
|
||||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) {
|
public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) {
|
||||||
for (WolfVariant wolfVariant : VALUES) {
|
for (BuiltInWolfVariant wolfVariant : VALUES) {
|
||||||
if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
|
if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
|
||||||
return wolfVariant;
|
return wolfVariant;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,9 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.level.block.property.Properties;
|
||||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
import org.geysermc.geyser.level.block.type.BedBlock;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData;
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData;
|
||||||
|
|
@ -119,28 +120,31 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The bed block
|
// The bed block
|
||||||
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
BlockState state = session.getGeyser().getWorldManager().blockAt(session, bedPosition);
|
||||||
String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.DEFAULT).getJavaIdentifier();
|
|
||||||
|
|
||||||
// Set the correct position offset and rotation when sleeping
|
// Set the correct position offset and rotation when sleeping
|
||||||
int bedRotation = 0;
|
int bedRotation = 0;
|
||||||
float xOffset = 0;
|
float xOffset = 0;
|
||||||
float zOffset = 0;
|
float zOffset = 0;
|
||||||
if (fullIdentifier.contains("facing=south")) {
|
if (state.block() instanceof BedBlock) {
|
||||||
// bed is facing south
|
switch (state.getValue(Properties.HORIZONTAL_FACING)) {
|
||||||
bedRotation = 180;
|
case SOUTH -> {
|
||||||
zOffset = -.5f;
|
bedRotation = 180;
|
||||||
} else if (fullIdentifier.contains("facing=east")) {
|
zOffset = -.5f;
|
||||||
// bed is facing east
|
}
|
||||||
bedRotation = 90;
|
case EAST -> {
|
||||||
xOffset = -.5f;
|
bedRotation = 90;
|
||||||
} else if (fullIdentifier.contains("facing=west")) {
|
xOffset = -.5f;
|
||||||
// bed is facing west
|
}
|
||||||
bedRotation = 270;
|
case WEST -> {
|
||||||
xOffset = .5f;
|
bedRotation = 270;
|
||||||
} else if (fullIdentifier.contains("facing=north")) {
|
xOffset = .5f;
|
||||||
// rotation does not change because north is 0
|
}
|
||||||
zOffset = .5f;
|
case NORTH -> {
|
||||||
|
// rotation does not change because north is 0
|
||||||
|
zOffset = .5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setYaw(yaw);
|
setYaw(yaw);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.entity.type.living.monster;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
|
import org.geysermc.geyser.item.Items;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.util.InteractionResult;
|
||||||
|
import org.geysermc.geyser.util.InteractiveTag;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class BoggedEntity extends AbstractSkeletonEntity {
|
||||||
|
private boolean sheared = false;
|
||||||
|
|
||||||
|
public BoggedEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSheared(BooleanEntityMetadata entityMetadata) {
|
||||||
|
this.sheared = entityMetadata.getPrimitiveValue();
|
||||||
|
setFlag(EntityFlag.SHEARED, this.sheared);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NonNull InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
|
||||||
|
if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
|
||||||
|
return InteractiveTag.SHEAR;
|
||||||
|
}
|
||||||
|
return super.testMobInteraction(hand, itemInHand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NonNull InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
|
||||||
|
if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
return super.mobInteract(hand, itemInHand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean readyForShearing() {
|
||||||
|
return !this.sheared && this.isAlive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.entity.type.living.monster;
|
||||||
|
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class BreezeEntity extends MonsterEntity {
|
||||||
|
public BreezeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPose(Pose pose) {
|
||||||
|
// TODO Test
|
||||||
|
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, pose == Pose.SHOOTING);
|
||||||
|
setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.INHALING);
|
||||||
|
super.setPose(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ public class ZoglinEntity extends MonsterEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canBeLeashed() {
|
public boolean canBeLeashed() {
|
||||||
return isNotLeashed();
|
return isNotLeashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.level.BedrockDimension;
|
import org.geysermc.geyser.level.BedrockDimension;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.AttributeUtils;
|
import org.geysermc.geyser.util.AttributeUtils;
|
||||||
|
|
@ -63,16 +64,14 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
protected final Map<GeyserAttributeType, AttributeData> attributes = new Object2ObjectOpenHashMap<>();
|
protected final Map<GeyserAttributeType, AttributeData> attributes = new Object2ObjectOpenHashMap<>();
|
||||||
/**
|
|
||||||
* Whether to check for updated speed after all entity metadata has been processed
|
|
||||||
*/
|
|
||||||
private boolean refreshSpeed = false;
|
|
||||||
/**
|
/**
|
||||||
* Used in PlayerInputTranslator for movement checks.
|
* Used in PlayerInputTranslator for movement checks.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private boolean isRidingInFront;
|
private boolean isRidingInFront;
|
||||||
|
|
||||||
|
private int lastAirSupply = getMaxAir();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if our position is currently out-of-sync with the Java server
|
* Determines if our position is currently out-of-sync with the Java server
|
||||||
* due to our workaround for the void floor
|
* due to our workaround for the void floor
|
||||||
|
|
@ -147,9 +146,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
// TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13)
|
// TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13)
|
||||||
if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) {
|
if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) {
|
||||||
super.setFlags(entityMetadata);
|
super.setFlags(entityMetadata);
|
||||||
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
|
|
||||||
}
|
}
|
||||||
refreshSpeed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -177,7 +174,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
public void setPose(Pose pose) {
|
public void setPose(Pose pose) {
|
||||||
super.setPose(pose);
|
super.setPose(pose);
|
||||||
session.setPose(pose);
|
session.setPose(pose);
|
||||||
refreshSpeed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getMaxHealth() {
|
public float getMaxHealth() {
|
||||||
|
|
@ -194,7 +190,13 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setAirSupply(int amount) {
|
protected void setAirSupply(int amount) {
|
||||||
if (amount == getMaxAir()) {
|
// Seemingly required to be sent as of Bedrock 1.21. Otherwise, bubbles will appear as empty
|
||||||
|
// Also, this changes how the air bubble graphics/sounds are presented. Breathing on means sound effects and
|
||||||
|
// the bubbles visually pop
|
||||||
|
setFlag(EntityFlag.BREATHING, amount >= this.lastAirSupply);
|
||||||
|
this.lastAirSupply = amount;
|
||||||
|
|
||||||
|
if (amount == getMaxAir() && GameProtocol.isPre1_21_0(session)) {
|
||||||
super.setAirSupply(0); // Hide the bubble counter from the UI for the player
|
super.setAirSupply(0); // Hide the bubble counter from the UI for the player
|
||||||
} else {
|
} else {
|
||||||
super.setAirSupply(amount);
|
super.setAirSupply(amount);
|
||||||
|
|
@ -226,21 +228,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBedrockMetadata() {
|
|
||||||
super.updateBedrockMetadata();
|
|
||||||
if (refreshSpeed) {
|
|
||||||
AttributeData speedAttribute = session.adjustSpeed();
|
|
||||||
if (speedAttribute != null) {
|
|
||||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
|
||||||
attributesPacket.setRuntimeEntityId(geyserId);
|
|
||||||
attributesPacket.setAttributes(Collections.singletonList(speedAttribute));
|
|
||||||
session.sendUpstreamPacket(attributesPacket);
|
|
||||||
}
|
|
||||||
refreshSpeed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
|
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
|
||||||
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
|
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
|
||||||
|
|
@ -253,17 +240,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
@Override
|
@Override
|
||||||
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
|
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
|
||||||
AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
|
AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
|
||||||
|
|
||||||
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_MOVEMENT_SPEED) {
|
|
||||||
session.setOriginalSpeedAttribute(attributeData.getValue());
|
|
||||||
AttributeData speedAttribute = session.adjustSpeed();
|
|
||||||
if (speedAttribute != null) {
|
|
||||||
// Overwrite the attribute with our own
|
|
||||||
this.attributes.put(type, speedAttribute);
|
|
||||||
return speedAttribute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.attributes.put(type, attributeData);
|
this.attributes.put(type, attributeData);
|
||||||
return attributeData;
|
return attributeData;
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +247,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
||||||
if (pos != null) {
|
if (pos != null) {
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
|
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension().asString()));
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true);
|
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true);
|
||||||
} else {
|
} else {
|
||||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.property.Properties;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
|
import org.geysermc.geyser.level.block.type.WallSkullBlock;
|
||||||
|
import org.geysermc.geyser.level.physics.Direction;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.SkullCache;
|
import org.geysermc.geyser.session.cache.SkullCache;
|
||||||
import org.geysermc.geyser.skin.SkullSkinManager;
|
import org.geysermc.geyser.skin.SkullSkinManager;
|
||||||
|
|
@ -137,20 +140,19 @@ public class SkullPlayerEntity extends PlayerEntity {
|
||||||
float z = skull.getPosition().getZ() + .5f;
|
float z = skull.getPosition().getZ() + .5f;
|
||||||
float rotation;
|
float rotation;
|
||||||
|
|
||||||
int blockState = skull.getBlockState();
|
BlockState blockState = skull.getBlockState();
|
||||||
byte floorRotation = BlockStateValues.getSkullRotation(blockState);
|
if (blockState.block() instanceof WallSkullBlock) {
|
||||||
if (floorRotation == -1) {
|
|
||||||
// Wall skull
|
|
||||||
y += 0.25f;
|
y += 0.25f;
|
||||||
rotation = BlockStateValues.getSkullWallDirections().get(blockState);
|
Direction direction = blockState.getValue(Properties.HORIZONTAL_FACING);
|
||||||
switch ((int) rotation) {
|
rotation = WallSkullBlock.getDegrees(direction);
|
||||||
case 180 -> z += 0.24f; // North
|
switch (direction) {
|
||||||
case 0 -> z -= 0.24f; // South
|
case NORTH -> z += 0.24f;
|
||||||
case 90 -> x += 0.24f; // West
|
case SOUTH -> z -= 0.24f;
|
||||||
case 270 -> x -= 0.24f; // East
|
case WEST -> x += 0.24f;
|
||||||
|
case EAST -> x -= 0.24f;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rotation = (180f + (floorRotation * 22.5f)) % 360;
|
rotation = (180f + (blockState.getValue(Properties.ROTATION_16) * 22.5f)) % 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true);
|
moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true);
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.erosion;
|
package org.geysermc.geyser.erosion;
|
||||||
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
|
|
@ -43,21 +42,18 @@ import org.geysermc.erosion.packet.ErosionPacketHandler;
|
||||||
import org.geysermc.erosion.packet.ErosionPacketSender;
|
import org.geysermc.erosion.packet.ErosionPacketSender;
|
||||||
import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
|
import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
|
||||||
import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
|
import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundBatchBlockIdPacket;
|
import org.geysermc.erosion.packet.geyserbound.*;
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockEntityPacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockIdPacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockLookupFailPacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundBlockPlacePacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundPickBlockPacket;
|
|
||||||
import org.geysermc.erosion.packet.geyserbound.GeyserboundPistonEventPacket;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
|
import org.geysermc.geyser.level.block.property.Properties;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.level.physics.Direction;
|
import org.geysermc.geyser.level.physics.Direction;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.PistonCache;
|
import org.geysermc.geyser.session.cache.PistonCache;
|
||||||
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
||||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
@ -71,7 +67,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
|
||||||
@Setter
|
@Setter
|
||||||
private CompletableFuture<int[]> pendingBatchLookup = null;
|
private CompletableFuture<int[]> pendingBatchLookup = null;
|
||||||
@Setter
|
@Setter
|
||||||
private CompletableFuture<DataComponents> pickBlockLookup = null;
|
private CompletableFuture<Int2ObjectMap<byte[]>> pickBlockLookup = null;
|
||||||
|
|
||||||
private final AtomicInteger nextTransactionId = new AtomicInteger(1);
|
private final AtomicInteger nextTransactionId = new AtomicInteger(1);
|
||||||
|
|
||||||
|
|
@ -127,7 +123,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
|
||||||
}
|
}
|
||||||
CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId);
|
CompletableFuture<Integer> future = this.asyncPendingLookups.remove(transactionId);
|
||||||
if (future != null) {
|
if (future != null) {
|
||||||
future.complete(BlockStateValues.JAVA_AIR_ID);
|
future.complete(Block.JAVA_AIR_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,28 +137,29 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
|
||||||
placeBlockSoundPacket.setIdentifier(":");
|
placeBlockSoundPacket.setIdentifier(":");
|
||||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||||
session.setLastBlockPlacePosition(null);
|
session.setLastBlockPlacePosition(null);
|
||||||
session.setLastBlockPlacedId(null);
|
session.setLastBlockPlaced(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePickBlock(GeyserboundPickBlockPacket packet) {
|
public void handlePickBlock(GeyserboundPickBlockPacket packet) {
|
||||||
if (this.pickBlockLookup != null) {
|
if (this.pickBlockLookup != null) {
|
||||||
//this.pickBlockLookup.complete(packet.getTag()); // TODO 1.20.5
|
this.pickBlockLookup.complete(packet.getComponents());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
|
public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
|
||||||
Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId());
|
Direction orientation = BlockState.of(packet.getBlockId()).getValue(Properties.FACING);
|
||||||
Vector3i position = packet.getPos();
|
Vector3i position = packet.getPos();
|
||||||
boolean isExtend = packet.isExtend();
|
boolean isExtend = packet.isExtend();
|
||||||
|
|
||||||
var stream = packet.getAttachedBlocks()
|
var stream = packet.getAttachedBlocks()
|
||||||
.object2IntEntrySet()
|
.object2IntEntrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend));
|
.map(entry -> Pair.of(entry.getKey(), BlockState.of(entry.getIntValue())))
|
||||||
Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>();
|
.filter(pair -> BlockStateValues.canPistonMoveBlock(pair.value(), isExtend));
|
||||||
stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue()));
|
Object2ObjectMap<Vector3i, BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
|
||||||
|
stream.forEach(pair -> attachedBlocks.put(pair.key(), pair.value()));
|
||||||
|
|
||||||
session.executeInEventLoop(() -> {
|
session.executeInEventLoop(() -> {
|
||||||
PistonCache pistonCache = session.getPistonCache();
|
PistonCache pistonCache = session.getPistonCache();
|
||||||
|
|
|
||||||
|
|
@ -32,24 +32,50 @@ import org.cloudburstmc.math.vector.Vector2f;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.CameraShakeAction;
|
import org.cloudburstmc.protocol.bedrock.data.CameraShakeAction;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.CameraShakeType;
|
import org.cloudburstmc.protocol.bedrock.data.CameraShakeType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.HudElement;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.HudVisibility;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.camera.CameraEase;
|
import org.cloudburstmc.protocol.bedrock.data.camera.CameraEase;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.camera.CameraFadeInstruction;
|
import org.cloudburstmc.protocol.bedrock.data.camera.CameraFadeInstruction;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.camera.CameraSetInstruction;
|
import org.cloudburstmc.protocol.bedrock.data.camera.CameraSetInstruction;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.CameraInstructionPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.CameraInstructionPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket;
|
import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket;
|
||||||
import org.geysermc.geyser.api.bedrock.camera.*;
|
import org.cloudburstmc.protocol.bedrock.packet.SetHudPacket;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraData;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraEaseType;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraFade;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraPerspective;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraPosition;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.GuiElement;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GeyserCameraData implements CameraData {
|
public class GeyserCameraData implements CameraData {
|
||||||
|
private static final HudElement[] HUD_ELEMENT_VALUES = HudElement.values();
|
||||||
|
private static final Set<HudElement> ALL_HUD_ELEMENTS = Set.of(HUD_ELEMENT_VALUES);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of elements to hide when the player is in spectator mode.
|
||||||
|
* Helps with tidying up the GUI; Java-style.
|
||||||
|
*/
|
||||||
|
private static final GuiElement[] SPECTATOR_HIDDEN_ELEMENTS = {
|
||||||
|
GuiElement.AIR_BUBBLES_BAR,
|
||||||
|
GuiElement.ARMOR,
|
||||||
|
GuiElement.HEALTH,
|
||||||
|
GuiElement.FOOD_BAR,
|
||||||
|
GuiElement.PROGRESS_BAR,
|
||||||
|
GuiElement.TOOL_TIPS
|
||||||
|
};
|
||||||
|
|
||||||
private final GeyserSession session;
|
private final GeyserSession session;
|
||||||
|
|
||||||
@Getter
|
|
||||||
private CameraPerspective cameraPerspective;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All fog effects that are currently applied to the client.
|
* All fog effects that are currently applied to the client.
|
||||||
*/
|
*/
|
||||||
|
|
@ -57,6 +83,14 @@ public class GeyserCameraData implements CameraData {
|
||||||
|
|
||||||
private final Set<UUID> cameraLockOwners = new HashSet<>();
|
private final Set<UUID> cameraLockOwners = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All currently hidden HUD elements
|
||||||
|
*/
|
||||||
|
private final Set<GuiElement> hiddenHudElements = new HashSet<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private CameraPerspective cameraPerspective;
|
||||||
|
|
||||||
public GeyserCameraData(GeyserSession session) {
|
public GeyserCameraData(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
@ -223,4 +257,67 @@ public class GeyserCameraData implements CameraData {
|
||||||
public boolean isCameraLocked() {
|
public boolean isCameraLocked() {
|
||||||
return !this.cameraLockOwners.isEmpty();
|
return !this.cameraLockOwners.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void hideElement(GuiElement... elements) {
|
||||||
|
Objects.requireNonNull(elements);
|
||||||
|
SetHudPacket packet = new SetHudPacket();
|
||||||
|
packet.setVisibility(HudVisibility.HIDE);
|
||||||
|
Set<HudElement> elementSet = packet.getElements();
|
||||||
|
|
||||||
|
for (GuiElement element : elements) {
|
||||||
|
this.hiddenHudElements.add(element);
|
||||||
|
elementSet.add(HUD_ELEMENT_VALUES[element.id()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetElement(GuiElement... elements) {
|
||||||
|
SetHudPacket packet = new SetHudPacket();
|
||||||
|
packet.setVisibility(HudVisibility.RESET);
|
||||||
|
Set<HudElement> elementSet = packet.getElements();
|
||||||
|
|
||||||
|
if (elements != null && elements.length != 0) {
|
||||||
|
for (GuiElement element : elements) {
|
||||||
|
this.hiddenHudElements.remove(element);
|
||||||
|
elementSet.add(HUD_ELEMENT_VALUES[element.id()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.hiddenHudElements.clear();
|
||||||
|
elementSet.addAll(ALL_HUD_ELEMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isHudElementHidden(@NonNull GuiElement element) {
|
||||||
|
Objects.requireNonNull(element);
|
||||||
|
return this.hiddenHudElements.contains(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull Set<GuiElement> hiddenElements() {
|
||||||
|
return Collections.unmodifiableSet(hiddenHudElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deals with hiding hud elements while in spectator.
|
||||||
|
*
|
||||||
|
* @param currentlySpectator whether the player is currently in spectator mode
|
||||||
|
* @param newGameMode the new GameMode to switch to
|
||||||
|
*/
|
||||||
|
public void handleGameModeChange(boolean currentlySpectator, GameMode newGameMode) {
|
||||||
|
if (newGameMode == GameMode.SPECTATOR) {
|
||||||
|
if (!currentlySpectator) {
|
||||||
|
hideElement(SPECTATOR_HIDDEN_ELEMENTS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentlySpectator) {
|
||||||
|
resetElement(SPECTATOR_HIDDEN_ELEMENTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory;
|
package org.geysermc.geyser.inventory;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
@ -37,7 +38,7 @@ import org.jetbrains.annotations.Range;
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class Container extends Inventory {
|
public class Container extends Inventory {
|
||||||
private final PlayerInventory playerInventory;
|
protected final PlayerInventory playerInventory;
|
||||||
private final int containerSize;
|
private final int containerSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -83,9 +84,9 @@ public class Container extends Inventory {
|
||||||
* Will be overwritten for droppers.
|
* Will be overwritten for droppers.
|
||||||
*
|
*
|
||||||
* @param usingRealBlock whether this container is using a real container or not
|
* @param usingRealBlock whether this container is using a real container or not
|
||||||
* @param javaBlockId the Java block string of the block, if real
|
* @param block the Java block, if real
|
||||||
*/
|
*/
|
||||||
public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) {
|
public void setUsingRealBlock(boolean usingRealBlock, Block block) {
|
||||||
isUsingRealBlock = usingRealBlock;
|
isUsingRealBlock = usingRealBlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,19 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory;
|
package org.geysermc.geyser.inventory;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.inventory.CrafterInventoryTranslator;
|
||||||
|
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.jetbrains.annotations.Range;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class CrafterContainer extends Container {
|
public class CrafterContainer extends Container {
|
||||||
|
private GeyserItemStack resultItem = GeyserItemStack.EMPTY;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean triggered = false;
|
private boolean triggered = false;
|
||||||
|
|
@ -46,8 +52,36 @@ public class CrafterContainer extends Container {
|
||||||
super(title, id, size, containerType, playerInventory);
|
super(title, id, size, containerType, playerInventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeyserItemStack getItem(int slot) {
|
||||||
|
if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
|
||||||
|
return this.resultItem;
|
||||||
|
} else if (isCraftingGrid(slot)) {
|
||||||
|
return super.getItem(slot);
|
||||||
|
} else {
|
||||||
|
return playerInventory.getItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) {
|
||||||
|
return playerInventory.getOffsetForHotbar(slot) - InventoryTranslator.PLAYER_INVENTORY_OFFSET + CrafterInventoryTranslator.GRID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
|
||||||
|
if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
|
||||||
|
// Result item probably won't be an item that needs to worry about net ID or lodestone compasses
|
||||||
|
this.resultItem = newItem;
|
||||||
|
} else if (isCraftingGrid(slot)) {
|
||||||
|
super.setItem(slot, newItem, session);
|
||||||
|
} else {
|
||||||
|
playerInventory.setItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET, newItem, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setSlot(int slot, boolean enabled) {
|
public void setSlot(int slot, boolean enabled) {
|
||||||
if (slot < 0 || slot > 8) {
|
if (!isCraftingGrid(slot)) {
|
||||||
GeyserImpl.getInstance().getLogger().warning("Crafter slot out of bounds: " + slot);
|
GeyserImpl.getInstance().getLogger().warning("Crafter slot out of bounds: " + slot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -58,4 +92,8 @@ public class CrafterContainer extends Container {
|
||||||
disabledSlotsMask = (short) (disabledSlotsMask | (1 << slot));
|
disabledSlotsMask = (short) (disabledSlotsMask | (1 << slot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isCraftingGrid(int slot) {
|
||||||
|
return slot >= 0 && slot <= 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
package org.geysermc.geyser.inventory;
|
package org.geysermc.geyser.inventory;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.geyser.level.block.Blocks;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator;
|
import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||||
|
|
@ -44,10 +46,10 @@ public class Generic3X3Container extends Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) {
|
public void setUsingRealBlock(boolean usingRealBlock, Block block) {
|
||||||
super.setUsingRealBlock(usingRealBlock, javaBlockId);
|
super.setUsingRealBlock(usingRealBlock, block);
|
||||||
if (usingRealBlock) {
|
if (usingRealBlock) {
|
||||||
isDropper = javaBlockId.startsWith("minecraft:dropper");
|
isDropper = block == Blocks.DROPPER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,11 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory;
|
package org.geysermc.geyser.inventory;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
|
||||||
import lombok.Getter;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -44,13 +43,13 @@ public class GeyserEnchantOption {
|
||||||
* is controlled by the server.
|
* is controlled by the server.
|
||||||
* So, of course, we have to throw in some easter eggs. ;)
|
* So, of course, we have to throw in some easter eggs. ;)
|
||||||
*/
|
*/
|
||||||
private static final List<String> ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better",
|
private static final List<String> ENCHANT_NAMES = List.of("tougher armor", "lukeeey", "fall better",
|
||||||
"explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa",
|
"explode less", "camo toy", "armor stab", "breathe better", "water walk", "rtm five one six", "oof ouch owie",
|
||||||
"tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
|
"enemy on fire", "spider sad", "aj ferguson", "redned", "more items thx", "fast tool", "give me block",
|
||||||
"more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft",
|
"less breaky break", "cube craft", "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser",
|
||||||
"strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this",
|
"come here fish", "you are elsa", "xp heals tools", "tim two zero three", "dragon proxy waz here",
|
||||||
"stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out",
|
"stabby stab", "supreme mortal", "i like this", "avatar i guess", "more arrows", "in and out",
|
||||||
"xp heals tools", "dragon proxy waz here");
|
"fly finder seventeen", "fast walk nether", "davchoo", "onechris", "death bringer thirteen", "kastle");
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int javaIndex;
|
private final int javaIndex;
|
||||||
|
|
@ -62,7 +61,6 @@ public class GeyserEnchantOption {
|
||||||
private boolean hasChanged;
|
private boolean hasChanged;
|
||||||
|
|
||||||
private int xpCost = 0;
|
private int xpCost = 0;
|
||||||
private int javaEnchantIndex = -1;
|
|
||||||
private int bedrockEnchantIndex = -1;
|
private int bedrockEnchantIndex = -1;
|
||||||
private int enchantLevel = -1;
|
private int enchantLevel = -1;
|
||||||
|
|
||||||
|
|
@ -74,7 +72,7 @@ public class GeyserEnchantOption {
|
||||||
this.hasChanged = false;
|
this.hasChanged = false;
|
||||||
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
|
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
|
||||||
enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
|
enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
|
||||||
javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
|
bedrockEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(bedrockEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasChanged() {
|
public boolean hasChanged() {
|
||||||
|
|
@ -88,10 +86,9 @@ public class GeyserEnchantOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnchantIndex(int javaEnchantIndex, int bedrockEnchantIndex) {
|
public void setEnchantIndex(int bedrockEnchantIndex) {
|
||||||
if (this.javaEnchantIndex != javaEnchantIndex) {
|
if (this.bedrockEnchantIndex != bedrockEnchantIndex) {
|
||||||
hasChanged = true;
|
hasChanged = true;
|
||||||
this.javaEnchantIndex = javaEnchantIndex;
|
|
||||||
this.bedrockEnchantIndex = bedrockEnchantIndex;
|
this.bedrockEnchantIndex = bedrockEnchantIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public class GeyserItemStack {
|
||||||
return of(javaId, amount, null);
|
return of(javaId, amount, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull GeyserItemStack of(int javaId, int amount, DataComponents components) {
|
public static @NonNull GeyserItemStack of(int javaId, int amount, @Nullable DataComponents components) {
|
||||||
return new GeyserItemStack(javaId, amount, components);
|
return new GeyserItemStack(javaId, amount, components);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.Container;
|
import org.geysermc.geyser.inventory.Container;
|
||||||
import org.geysermc.geyser.inventory.Inventory;
|
import org.geysermc.geyser.inventory.Inventory;
|
||||||
import org.geysermc.geyser.inventory.LecternContainer;
|
import org.geysermc.geyser.inventory.LecternContainer;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
|
import org.geysermc.geyser.level.block.type.BlockState;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.registry.type.BlockMapping;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||||
import org.geysermc.geyser.util.BlockUtils;
|
|
||||||
import org.geysermc.geyser.util.InventoryUtils;
|
import org.geysermc.geyser.util.InventoryUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -55,20 +55,24 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
/**
|
/**
|
||||||
* The default Java block ID to translate as a fake block
|
* The default Java block ID to translate as a fake block
|
||||||
*/
|
*/
|
||||||
private final int defaultJavaBlockState;
|
private final BlockState defaultJavaBlockState;
|
||||||
private final ContainerType containerType;
|
private final ContainerType containerType;
|
||||||
private final Set<String> validBlocks;
|
private final Set<Block> validBlocks;
|
||||||
|
|
||||||
public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) {
|
public BlockInventoryHolder(Block defaultJavaBlock, ContainerType containerType, Block... validBlocks) {
|
||||||
this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier);
|
this(defaultJavaBlock.defaultBlockState(), containerType, validBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockInventoryHolder(BlockState defaultJavaBlockState, ContainerType containerType, Block... validBlocks) {
|
||||||
|
this.defaultJavaBlockState = defaultJavaBlockState;
|
||||||
this.containerType = containerType;
|
this.containerType = containerType;
|
||||||
if (validBlocks != null) {
|
if (validBlocks != null) {
|
||||||
Set<String> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
|
Set<Block> validBlocksTemp = new HashSet<>(validBlocks.length + 1);
|
||||||
Collections.addAll(validBlocksTemp, validBlocks);
|
Collections.addAll(validBlocksTemp, validBlocks);
|
||||||
validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
|
validBlocksTemp.add(defaultJavaBlockState.block());
|
||||||
this.validBlocks = Set.copyOf(validBlocksTemp);
|
this.validBlocks = Set.copyOf(validBlocksTemp);
|
||||||
} else {
|
} else {
|
||||||
this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
|
this.validBlocks = Collections.singleton(defaultJavaBlockState.block());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,14 +84,13 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
if (checkInteractionPosition(session)) {
|
if (checkInteractionPosition(session)) {
|
||||||
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
|
||||||
// and the bedrock block is vanilla
|
// and the bedrock block is vanilla
|
||||||
int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
|
BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition());
|
||||||
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(javaBlockId)) {
|
if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
|
||||||
String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.DEFAULT).getJavaIdentifier().split("\\[");
|
if (isValidBlock(state)) {
|
||||||
if (isValidBlock(javaBlockString)) {
|
|
||||||
// We can safely use this block
|
// We can safely use this block
|
||||||
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
|
||||||
((Container) inventory).setUsingRealBlock(true, javaBlockString[0]);
|
((Container) inventory).setUsingRealBlock(true, state.block());
|
||||||
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId);
|
setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -125,11 +128,11 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
/**
|
/**
|
||||||
* @return true if this Java block ID can be used for player inventory.
|
* @return true if this Java block ID can be used for player inventory.
|
||||||
*/
|
*/
|
||||||
protected boolean isValidBlock(String[] javaBlockString) {
|
protected boolean isValidBlock(BlockState blockState) {
|
||||||
return this.validBlocks.contains(javaBlockString[0]);
|
return this.validBlocks.contains(blockState.block());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) {
|
protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) {
|
||||||
NbtMap tag = NbtMap.builder()
|
NbtMap tag = NbtMap.builder()
|
||||||
.putInt("x", position.getX())
|
.putInt("x", position.getX())
|
||||||
.putInt("y", position.getY())
|
.putInt("y", position.getY())
|
||||||
|
|
@ -160,6 +163,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
ContainerClosePacket packet = new ContainerClosePacket();
|
ContainerClosePacket packet = new ContainerClosePacket();
|
||||||
packet.setId((byte) inventory.getBedrockId());
|
packet.setId((byte) inventory.getBedrockId());
|
||||||
packet.setServerInitiated(true);
|
packet.setServerInitiated(true);
|
||||||
|
packet.setType(ContainerType.CONTAINER);
|
||||||
session.sendUpstreamPacket(packet);
|
session.sendUpstreamPacket(packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@
|
||||||
package org.geysermc.geyser.inventory.item;
|
package org.geysermc.geyser.inventory.item;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.util.MinecraftKey;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
|
@ -72,21 +74,23 @@ public enum BannerPattern {
|
||||||
SKULL("sku"),
|
SKULL("sku"),
|
||||||
FLOWER("flo"),
|
FLOWER("flo"),
|
||||||
MOJANG("moj"),
|
MOJANG("moj"),
|
||||||
PIGLIN("pig");
|
PIGLIN("pig"),
|
||||||
|
FLOW("flw"),
|
||||||
|
GUSTER("gus");
|
||||||
|
|
||||||
private static final BannerPattern[] VALUES = values();
|
private static final BannerPattern[] VALUES = values();
|
||||||
|
|
||||||
private final String javaIdentifier;
|
private final Key javaIdentifier;
|
||||||
private final String bedrockIdentifier;
|
private final String bedrockIdentifier;
|
||||||
|
|
||||||
BannerPattern(String bedrockIdentifier) {
|
BannerPattern(String bedrockIdentifier) {
|
||||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT));
|
||||||
this.bedrockIdentifier = bedrockIdentifier;
|
this.bedrockIdentifier = bedrockIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable BannerPattern getByJavaIdentifier(String javaIdentifier) {
|
public static @Nullable BannerPattern getByJavaIdentifier(Key key) {
|
||||||
for (BannerPattern bannerPattern : VALUES) {
|
for (BannerPattern bannerPattern : VALUES) {
|
||||||
if (bannerPattern.javaIdentifier.equals(javaIdentifier)) {
|
if (bannerPattern.javaIdentifier.equals(key)) {
|
||||||
return bannerPattern;
|
return bannerPattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,11 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory.item;
|
package org.geysermc.geyser.inventory.item;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@Getter
|
public enum BedrockEnchantment {
|
||||||
public enum Enchantment {
|
|
||||||
PROTECTION,
|
PROTECTION,
|
||||||
FIRE_PROTECTION,
|
FIRE_PROTECTION,
|
||||||
FEATHER_FALLING,
|
FEATHER_FALLING,
|
||||||
|
|
@ -69,18 +67,21 @@ public enum Enchantment {
|
||||||
PIERCING,
|
PIERCING,
|
||||||
QUICK_CHARGE,
|
QUICK_CHARGE,
|
||||||
SOUL_SPEED,
|
SOUL_SPEED,
|
||||||
SWIFT_SNEAK;
|
SWIFT_SNEAK,
|
||||||
|
WIND_BURST,
|
||||||
|
DENSITY,
|
||||||
|
BREACH;
|
||||||
|
|
||||||
private static final Enchantment[] VALUES = values();
|
private static final BedrockEnchantment[] VALUES = values();
|
||||||
|
|
||||||
private final String javaIdentifier;
|
private final String javaIdentifier;
|
||||||
|
|
||||||
Enchantment() {
|
BedrockEnchantment() {
|
||||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable Enchantment getByJavaIdentifier(String javaIdentifier) {
|
public static @Nullable BedrockEnchantment getByJavaIdentifier(String javaIdentifier) {
|
||||||
for (Enchantment enchantment : VALUES) {
|
for (BedrockEnchantment enchantment : VALUES) {
|
||||||
if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) {
|
if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) {
|
||||||
return enchantment;
|
return enchantment;
|
||||||
}
|
}
|
||||||
|
|
@ -88,88 +89,10 @@ public enum Enchantment {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable Enchantment getByBedrockId(int bedrockId) {
|
public static @Nullable BedrockEnchantment getByBedrockId(int bedrockId) {
|
||||||
if (bedrockId >= 0 && bedrockId < VALUES.length) {
|
if (bedrockId >= 0 && bedrockId < VALUES.length) {
|
||||||
return VALUES[bedrockId];
|
return VALUES[bedrockId];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enchantments classified by their Java index
|
|
||||||
*/
|
|
||||||
public enum JavaEnchantment {
|
|
||||||
PROTECTION,
|
|
||||||
FIRE_PROTECTION,
|
|
||||||
FEATHER_FALLING,
|
|
||||||
BLAST_PROTECTION,
|
|
||||||
PROJECTILE_PROTECTION,
|
|
||||||
RESPIRATION,
|
|
||||||
AQUA_AFFINITY,
|
|
||||||
THORNS,
|
|
||||||
DEPTH_STRIDER,
|
|
||||||
FROST_WALKER,
|
|
||||||
BINDING_CURSE,
|
|
||||||
SOUL_SPEED,
|
|
||||||
SWIFT_SNEAK,
|
|
||||||
SHARPNESS,
|
|
||||||
SMITE,
|
|
||||||
BANE_OF_ARTHROPODS,
|
|
||||||
KNOCKBACK,
|
|
||||||
FIRE_ASPECT,
|
|
||||||
LOOTING,
|
|
||||||
SWEEPING_EDGE,
|
|
||||||
EFFICIENCY,
|
|
||||||
SILK_TOUCH,
|
|
||||||
UNBREAKING,
|
|
||||||
FORTUNE,
|
|
||||||
POWER,
|
|
||||||
PUNCH,
|
|
||||||
FLAME,
|
|
||||||
INFINITY,
|
|
||||||
LUCK_OF_THE_SEA,
|
|
||||||
LURE,
|
|
||||||
LOYALTY,
|
|
||||||
IMPALING,
|
|
||||||
RIPTIDE,
|
|
||||||
CHANNELING,
|
|
||||||
MULTISHOT,
|
|
||||||
QUICK_CHARGE,
|
|
||||||
PIERCING,
|
|
||||||
DENSITY,
|
|
||||||
BREACH,
|
|
||||||
WIND_BURST,
|
|
||||||
MENDING,
|
|
||||||
VANISHING_CURSE;
|
|
||||||
|
|
||||||
private static final JavaEnchantment[] VALUES = JavaEnchantment.values();
|
|
||||||
|
|
||||||
public static JavaEnchantment of(int index) {
|
|
||||||
return VALUES[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of all enchantment Java identifiers for use with command suggestions.
|
|
||||||
*/
|
|
||||||
public static final String[] ALL_JAVA_IDENTIFIERS;
|
|
||||||
|
|
||||||
public static @Nullable JavaEnchantment getByJavaIdentifier(String javaIdentifier) {
|
|
||||||
if (!javaIdentifier.startsWith("minecraft:")) {
|
|
||||||
javaIdentifier = "minecraft:" + javaIdentifier;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
|
||||||
if (ALL_JAVA_IDENTIFIERS[i].equalsIgnoreCase(javaIdentifier)) {
|
|
||||||
return VALUES[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
ALL_JAVA_IDENTIFIERS = new String[VALUES.length];
|
|
||||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
|
||||||
ALL_JAVA_IDENTIFIERS[i] = "minecraft:" + VALUES[i].name().toLowerCase(Locale.ENGLISH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -34,63 +34,83 @@ import java.util.Locale;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public enum Potion {
|
public enum Potion {
|
||||||
WATER(0),
|
WATER(0, ArrowParticleColors.NONE),
|
||||||
MUNDANE(1),
|
MUNDANE(1, ArrowParticleColors.NONE), // 2 is extended?
|
||||||
THICK(3),
|
THICK(3, ArrowParticleColors.NONE),
|
||||||
AWKWARD(4),
|
AWKWARD(4, ArrowParticleColors.NONE),
|
||||||
NIGHT_VISION(5),
|
NIGHT_VISION(5, ArrowParticleColors.NIGHT_VISION),
|
||||||
LONG_NIGHT_VISION(6),
|
LONG_NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
|
||||||
INVISIBILITY(7),
|
INVISIBILITY(7, ArrowParticleColors.INVISIBILITY),
|
||||||
LONG_INVISIBILITY(8),
|
LONG_INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
|
||||||
LEAPING(9),
|
LEAPING(9, ArrowParticleColors.LEAPING),
|
||||||
LONG_LEAPING(10),
|
LONG_LEAPING(10, ArrowParticleColors.LEAPING),
|
||||||
STRONG_LEAPING(11),
|
STRONG_LEAPING(11, ArrowParticleColors.LEAPING),
|
||||||
FIRE_RESISTANCE(12),
|
FIRE_RESISTANCE(12, ArrowParticleColors.FIRE_RESISTANCE),
|
||||||
LONG_FIRE_RESISTANCE(13),
|
LONG_FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
|
||||||
SWIFTNESS(14),
|
SWIFTNESS(14, ArrowParticleColors.SWIFTNESS),
|
||||||
LONG_SWIFTNESS(15),
|
LONG_SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
|
||||||
STRONG_SWIFTNESS(16),
|
STRONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
|
||||||
SLOWNESS(17),
|
SLOWNESS(17, ArrowParticleColors.SLOWNESS),
|
||||||
LONG_SLOWNESS(18),
|
LONG_SLOWNESS(18, ArrowParticleColors.SLOWNESS),
|
||||||
STRONG_SLOWNESS(42),
|
STRONG_SLOWNESS(42, ArrowParticleColors.SLOWNESS),
|
||||||
TURTLE_MASTER(37),
|
TURTLE_MASTER(37, ArrowParticleColors.TURTLE_MASTER),
|
||||||
LONG_TURTLE_MASTER(38),
|
LONG_TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
|
||||||
STRONG_TURTLE_MASTER(39),
|
STRONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
|
||||||
WATER_BREATHING(19),
|
WATER_BREATHING(19, ArrowParticleColors.WATER_BREATHING),
|
||||||
LONG_WATER_BREATHING(20),
|
LONG_WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
|
||||||
HEALING(21),
|
HEALING(21, ArrowParticleColors.HEALING),
|
||||||
STRONG_HEALING(22),
|
STRONG_HEALING(22, ArrowParticleColors.HEALING),
|
||||||
HARMING(23),
|
HARMING(23, ArrowParticleColors.HARMING),
|
||||||
STRONG_HARMING(24),
|
STRONG_HARMING(24, ArrowParticleColors.HARMING),
|
||||||
POISON(25),
|
POISON(25, ArrowParticleColors.POISON),
|
||||||
LONG_POISON(26),
|
LONG_POISON(26, ArrowParticleColors.POISON),
|
||||||
STRONG_POISON(27),
|
STRONG_POISON(27, ArrowParticleColors.POISON),
|
||||||
REGENERATION(28),
|
REGENERATION(28, ArrowParticleColors.REGENERATION),
|
||||||
LONG_REGENERATION(29),
|
LONG_REGENERATION(29, ArrowParticleColors.REGENERATION),
|
||||||
STRONG_REGENERATION(30),
|
STRONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
|
||||||
STRENGTH(31),
|
STRENGTH(31, ArrowParticleColors.STRENGTH),
|
||||||
LONG_STRENGTH(32),
|
LONG_STRENGTH(32, ArrowParticleColors.STRENGTH),
|
||||||
STRONG_STRENGTH(33),
|
STRONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
|
||||||
WEAKNESS(34),
|
WEAKNESS(34, ArrowParticleColors.WEAKNESS),
|
||||||
LONG_WEAKNESS(35),
|
LONG_WEAKNESS(35, ArrowParticleColors.WEAKNESS),
|
||||||
LUCK(2), //does not exist
|
LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
|
||||||
SLOW_FALLING(40),
|
SLOW_FALLING(40, ArrowParticleColors.SLOW_FALLING),
|
||||||
LONG_SLOW_FALLING(41);
|
LONG_SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
|
||||||
|
WIND_CHARGING(43, ArrowParticleColors.WIND_CHARGING),
|
||||||
|
WEAVING(44, ArrowParticleColors.WEAVING),
|
||||||
|
OOZING(45, ArrowParticleColors.OOZING),
|
||||||
|
INFESTATION(46, ArrowParticleColors.INFESTATION);
|
||||||
|
|
||||||
public static final Potion[] VALUES = values();
|
public static final Potion[] VALUES = values();
|
||||||
|
|
||||||
private final String javaIdentifier;
|
private final String javaIdentifier;
|
||||||
private final short bedrockId;
|
private final short bedrockId;
|
||||||
|
private final int javaColor;
|
||||||
|
|
||||||
Potion(int bedrockId) {
|
Potion(int bedrockId, int javaColor) {
|
||||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||||
this.bedrockId = (short) bedrockId;
|
this.bedrockId = (short) bedrockId;
|
||||||
|
this.javaColor = javaColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int tippedArrowId() {
|
||||||
|
// +1 likely to offset 0 as nothing?
|
||||||
|
return this.bedrockId + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PotionContents toComponent() {
|
public PotionContents toComponent() {
|
||||||
return new PotionContents(this.ordinal(), -1, Collections.emptyList());
|
return new PotionContents(this.ordinal(), -1, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Potion getByJavaIdentifier(String javaIdentifier) {
|
||||||
|
for (Potion potion : VALUES) {
|
||||||
|
if (potion.javaIdentifier.equals(javaIdentifier)) {
|
||||||
|
return potion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static @Nullable Potion getByJavaId(int javaId) {
|
public static @Nullable Potion getByJavaId(int javaId) {
|
||||||
if (javaId >= 0 && javaId < VALUES.length) {
|
if (javaId >= 0 && javaId < VALUES.length) {
|
||||||
return VALUES[javaId];
|
return VALUES[javaId];
|
||||||
|
|
@ -106,4 +126,44 @@ public enum Potion {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @Nullable Potion getByTippedArrowDamage(int bedrockId) {
|
||||||
|
return getByBedrockId(bedrockId - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte toTippedArrowId(int javaParticleColor) {
|
||||||
|
for (Potion potion : VALUES) {
|
||||||
|
if (potion.javaColor == javaParticleColor) {
|
||||||
|
return (byte) (potion.bedrockId + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (byte) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For tipped arrow usage
|
||||||
|
*/
|
||||||
|
private static final class ArrowParticleColors {
|
||||||
|
static final int NONE = 1;
|
||||||
|
static final int NIGHT_VISION = 2039713;
|
||||||
|
static final int INVISIBILITY = 8356754;
|
||||||
|
static final int LEAPING = 2293580;
|
||||||
|
static final int FIRE_RESISTANCE = 14981690;
|
||||||
|
static final int SWIFTNESS = 8171462;
|
||||||
|
static final int SLOWNESS = 5926017;
|
||||||
|
static final int TURTLE_MASTER = 7691106;
|
||||||
|
static final int WATER_BREATHING = 3035801;
|
||||||
|
static final int HEALING = 16262179;
|
||||||
|
static final int HARMING = 4393481;
|
||||||
|
static final int POISON = 5149489;
|
||||||
|
static final int REGENERATION = 13458603;
|
||||||
|
static final int STRENGTH = 9643043;
|
||||||
|
static final int WEAKNESS = 4738376;
|
||||||
|
static final int LUCK = 3381504;
|
||||||
|
static final int SLOW_FALLING = 16773073;
|
||||||
|
static final int WIND_CHARGING = 12438015;
|
||||||
|
static final int WEAVING = 7891290;
|
||||||
|
static final int OOZING = 10092451;
|
||||||
|
static final int INFESTATION = 9214860;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* @author GeyserMC
|
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory.item;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Potion identifiers and their respective Bedrock IDs used with arrows.
|
|
||||||
* <a href="https://minecraft.wiki/w/Arrow#Data_values">See here</a>
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum TippedArrowPotion {
|
|
||||||
WATER(-1, ArrowParticleColors.NONE), // Guessing this based off of the Potion enum. TODO merge?
|
|
||||||
MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended?
|
|
||||||
THICK(4, ArrowParticleColors.NONE),
|
|
||||||
AWKWARD(5, ArrowParticleColors.NONE),
|
|
||||||
NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
|
|
||||||
LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION),
|
|
||||||
INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
|
|
||||||
LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY),
|
|
||||||
LEAPING(10, ArrowParticleColors.LEAPING),
|
|
||||||
LONG_LEAPING(11, ArrowParticleColors.LEAPING),
|
|
||||||
STRONG_LEAPING(12, ArrowParticleColors.LEAPING),
|
|
||||||
FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
|
|
||||||
LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE),
|
|
||||||
SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
|
|
||||||
LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
|
|
||||||
STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS),
|
|
||||||
SLOWNESS(18, ArrowParticleColors.SLOWNESS),
|
|
||||||
LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS),
|
|
||||||
STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS),
|
|
||||||
WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
|
|
||||||
LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING),
|
|
||||||
HEALING(22, ArrowParticleColors.HEALING),
|
|
||||||
STRONG_HEALING(23, ArrowParticleColors.HEALING),
|
|
||||||
HARMING(24, ArrowParticleColors.HARMING),
|
|
||||||
STRONG_HARMING(25, ArrowParticleColors.HARMING),
|
|
||||||
POISON(26, ArrowParticleColors.POISON),
|
|
||||||
LONG_POISON(27, ArrowParticleColors.POISON),
|
|
||||||
STRONG_POISON(28, ArrowParticleColors.POISON),
|
|
||||||
REGENERATION(29, ArrowParticleColors.REGENERATION),
|
|
||||||
LONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
|
|
||||||
STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION),
|
|
||||||
STRENGTH(32, ArrowParticleColors.STRENGTH),
|
|
||||||
LONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
|
|
||||||
STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH),
|
|
||||||
WEAKNESS(35, ArrowParticleColors.WEAKNESS),
|
|
||||||
LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS),
|
|
||||||
LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
|
|
||||||
TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
|
|
||||||
LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
|
|
||||||
STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER),
|
|
||||||
SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
|
|
||||||
LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING);
|
|
||||||
|
|
||||||
private static final TippedArrowPotion[] VALUES = values();
|
|
||||||
|
|
||||||
private final String javaIdentifier;
|
|
||||||
private final short bedrockId;
|
|
||||||
/**
|
|
||||||
* The Java color associated with this ID.
|
|
||||||
* Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock
|
|
||||||
*/
|
|
||||||
private final int javaColor;
|
|
||||||
|
|
||||||
TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) {
|
|
||||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
|
||||||
this.bedrockId = (short) bedrockId;
|
|
||||||
this.javaColor = arrowParticleColor.getColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @Nullable TippedArrowPotion of(int id) {
|
|
||||||
if (id >= 0 && id < VALUES.length) {
|
|
||||||
return VALUES[id];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) {
|
|
||||||
for (TippedArrowPotion potion : VALUES) {
|
|
||||||
if (potion.bedrockId == bedrockId) {
|
|
||||||
return potion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param color the potion color to look up
|
|
||||||
* @return the tipped arrow potion that most closely resembles that color.
|
|
||||||
*/
|
|
||||||
public static @Nullable TippedArrowPotion getByJavaColor(int color) {
|
|
||||||
for (TippedArrowPotion potion : VALUES) {
|
|
||||||
if (potion.javaColor == color) {
|
|
||||||
return potion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ArrowParticleColors {
|
|
||||||
NONE(-1),
|
|
||||||
NIGHT_VISION(2039713),
|
|
||||||
INVISIBILITY(8356754),
|
|
||||||
LEAPING(2293580),
|
|
||||||
FIRE_RESISTANCE(14981690),
|
|
||||||
SWIFTNESS(8171462),
|
|
||||||
SLOWNESS(5926017),
|
|
||||||
TURTLE_MASTER(7691106),
|
|
||||||
WATER_BREATHING(3035801),
|
|
||||||
HEALING(16262179),
|
|
||||||
HARMING(4393481),
|
|
||||||
POISON(5149489),
|
|
||||||
REGENERATION(13458603),
|
|
||||||
STRENGTH(9643043),
|
|
||||||
WEAKNESS(4738376),
|
|
||||||
LUCK(3381504),
|
|
||||||
SLOW_FALLING(16773073);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final int color;
|
|
||||||
|
|
||||||
ArrowParticleColors(int color) {
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -25,6 +25,9 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.inventory.recipe;
|
package org.geysermc.geyser.inventory.recipe;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}.
|
* A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,4 +36,7 @@ public interface GeyserRecipe {
|
||||||
* Whether the recipe is flexible or not in which items can be placed where.
|
* Whether the recipe is flexible or not in which items can be placed where.
|
||||||
*/
|
*/
|
||||||
boolean isShaped();
|
boolean isShaped();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
ItemStack result();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public final class TrimRecipe {
|
||||||
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
|
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
|
||||||
|
|
||||||
public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
|
public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
|
||||||
String key = stripMinecraftNamespace(entry.getId());
|
String key = entry.getId().asMinimalString();
|
||||||
|
|
||||||
// Color is used when hovering over the item
|
// Color is used when hovering over the item
|
||||||
// Find the nearest legacy color from the RGB Java gives us to work with
|
// Find the nearest legacy color from the RGB Java gives us to work with
|
||||||
|
|
@ -67,7 +67,7 @@ public final class TrimRecipe {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
|
public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
|
||||||
String key = stripMinecraftNamespace(entry.getId());
|
String key = entry.getId().asMinimalString();
|
||||||
|
|
||||||
String itemIdentifier = entry.getData().getString("template_item");
|
String itemIdentifier = entry.getData().getString("template_item");
|
||||||
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
|
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
|
||||||
|
|
@ -78,19 +78,6 @@ public final class TrimRecipe {
|
||||||
return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
|
return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO find a good place for a stripNamespace util method
|
|
||||||
private static String stripMinecraftNamespace(String identifier) {
|
|
||||||
int i = identifier.indexOf(':');
|
|
||||||
if (i >= 0) {
|
|
||||||
String namespace = identifier.substring(0, i);
|
|
||||||
// Only strip minecraft namespace
|
|
||||||
if (namespace.equals("minecraft")) {
|
|
||||||
return identifier.substring(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TrimRecipe() {
|
private TrimRecipe() {
|
||||||
//no-op
|
//no-op
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
package org.geysermc.geyser.inventory.updater;
|
package org.geysermc.geyser.inventory.updater;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
|
|
@ -38,10 +37,9 @@ import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.AnvilContainer;
|
import org.geysermc.geyser.inventory.AnvilContainer;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.inventory.Inventory;
|
import org.geysermc.geyser.inventory.Inventory;
|
||||||
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||||
|
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
|
||||||
import org.geysermc.geyser.registry.type.EnchantmentData;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
|
|
@ -307,22 +305,22 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||||
*/
|
*/
|
||||||
private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) {
|
private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) {
|
||||||
boolean hasCompatible = false;
|
boolean hasCompatible = false;
|
||||||
Object2IntMap<JavaEnchantment> combinedEnchantments = getEnchantments(input);
|
Object2IntMap<Enchantment> combinedEnchantments = getEnchantments(session, input);
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
for (Object2IntMap.Entry<JavaEnchantment> entry : getEnchantments(material).object2IntEntrySet()) {
|
for (Object2IntMap.Entry<Enchantment> entry : getEnchantments(session, material).object2IntEntrySet()) {
|
||||||
JavaEnchantment enchantment = entry.getKey();
|
Enchantment enchantment = entry.getKey();
|
||||||
EnchantmentData data = Registries.ENCHANTMENTS.get(enchantment);
|
|
||||||
if (data == null) {
|
|
||||||
GeyserImpl.getInstance().getLogger().debug("Java enchantment not in registry: " + enchantment);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean canApply = isEnchantedBook(input) || data.validItems().contains(input.getJavaId());
|
boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input);
|
||||||
for (JavaEnchantment incompatible : data.incompatibleEnchantments()) {
|
var exclusiveSet = enchantment.exclusiveSet();
|
||||||
if (combinedEnchantments.containsKey(incompatible)) {
|
if (exclusiveSet != null) {
|
||||||
canApply = false;
|
int[] incompatibleEnchantments = session.getTagCache().get(exclusiveSet);
|
||||||
if (!bedrock) {
|
for (int i : incompatibleEnchantments) {
|
||||||
cost++;
|
Enchantment incompatible = session.getRegistryCache().enchantments().byId(i);
|
||||||
|
if (combinedEnchantments.containsKey(incompatible)) {
|
||||||
|
canApply = false;
|
||||||
|
if (!bedrock) {
|
||||||
|
cost++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -334,12 +332,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||||
newLevel++;
|
newLevel++;
|
||||||
}
|
}
|
||||||
newLevel = Math.max(currentLevel, newLevel);
|
newLevel = Math.max(currentLevel, newLevel);
|
||||||
if (newLevel > data.maxLevel()) {
|
if (newLevel > enchantment.maxLevel()) {
|
||||||
newLevel = data.maxLevel();
|
newLevel = enchantment.maxLevel();
|
||||||
}
|
}
|
||||||
combinedEnchantments.put(enchantment, newLevel);
|
combinedEnchantments.put(enchantment, newLevel);
|
||||||
|
|
||||||
int rarityMultiplier = data.rarityMultiplier();
|
int rarityMultiplier = enchantment.anvilCost();
|
||||||
if (isEnchantedBook(material) && rarityMultiplier > 1) {
|
if (isEnchantedBook(material) && rarityMultiplier > 1) {
|
||||||
rarityMultiplier /= 2;
|
rarityMultiplier /= 2;
|
||||||
}
|
}
|
||||||
|
|
@ -347,11 +345,11 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||||
if (newLevel > currentLevel) {
|
if (newLevel > currentLevel) {
|
||||||
hasCompatible = true;
|
hasCompatible = true;
|
||||||
}
|
}
|
||||||
if (enchantment == JavaEnchantment.IMPALING) {
|
if (enchantment.bedrockEnchantment() == BedrockEnchantment.IMPALING) {
|
||||||
// Multiplier is halved on Bedrock for some reason
|
// Multiplier is halved on Bedrock for some reason
|
||||||
rarityMultiplier /= 2;
|
rarityMultiplier /= 2;
|
||||||
} else if (enchantment == JavaEnchantment.SWEEPING_EDGE) {
|
} else if (enchantment.bedrockEnchantment() == null) {
|
||||||
// Doesn't exist on Bedrock
|
// Whatever this is, doesn't exist on Bedrock
|
||||||
rarityMultiplier = 0;
|
rarityMultiplier = 0;
|
||||||
}
|
}
|
||||||
cost += rarityMultiplier * (newLevel - currentLevel);
|
cost += rarityMultiplier * (newLevel - currentLevel);
|
||||||
|
|
@ -368,7 +366,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object2IntMap<JavaEnchantment> getEnchantments(GeyserItemStack itemStack) {
|
private Object2IntMap<Enchantment> getEnchantments(GeyserSession session, GeyserItemStack itemStack) {
|
||||||
ItemEnchantments enchantmentComponent;
|
ItemEnchantments enchantmentComponent;
|
||||||
if (isEnchantedBook(itemStack)) {
|
if (isEnchantedBook(itemStack)) {
|
||||||
enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS);
|
enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS);
|
||||||
|
|
@ -376,9 +374,9 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
||||||
enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS);
|
enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS);
|
||||||
}
|
}
|
||||||
if (enchantmentComponent != null) {
|
if (enchantmentComponent != null) {
|
||||||
Object2IntMap<JavaEnchantment> enchantments = new Object2IntOpenHashMap<>();
|
Object2IntMap<Enchantment> enchantments = new Object2IntOpenHashMap<>();
|
||||||
for (Map.Entry<Integer, Integer> entry : enchantmentComponent.getEnchantments().entrySet()) {
|
for (Map.Entry<Integer, Integer> entry : enchantmentComponent.getEnchantments().entrySet()) {
|
||||||
JavaEnchantment enchantment = JavaEnchantment.of(entry.getKey());
|
Enchantment enchantment = session.getRegistryCache().enchantments().byId(entry.getKey());
|
||||||
if (enchantment == null) {
|
if (enchantment == null) {
|
||||||
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey());
|
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey());
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.item.enchantment;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
|
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||||
|
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||||
|
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||||
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
|
import org.geysermc.geyser.util.MinecraftKey;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description only populated if {@link #bedrockEnchantment()} is not null.
|
||||||
|
* @param anvilCost also as a rarity multiplier
|
||||||
|
*/
|
||||||
|
public record Enchantment(String identifier,
|
||||||
|
Set<EnchantmentComponent> effects,
|
||||||
|
ItemTag supportedItems,
|
||||||
|
int maxLevel,
|
||||||
|
String description,
|
||||||
|
int anvilCost,
|
||||||
|
@Nullable EnchantmentTag exclusiveSet,
|
||||||
|
@Nullable BedrockEnchantment bedrockEnchantment) {
|
||||||
|
|
||||||
|
// Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes.
|
||||||
|
// I'm not sure how that's wired over the network, so we'll put it off.
|
||||||
|
public static Enchantment read(RegistryEntry entry) {
|
||||||
|
NbtMap data = entry.getData();
|
||||||
|
Set<EnchantmentComponent> effects = readEnchantmentComponents(data.getCompound("effects"));
|
||||||
|
String supportedItems = data.getString("supported_items").substring(1); // Remove '#' at beginning that indicates tag
|
||||||
|
int maxLevel = data.getInt("max_level");
|
||||||
|
int anvilCost = data.getInt("anvil_cost");
|
||||||
|
String exclusiveSet = data.getString("exclusive_set", null);
|
||||||
|
EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1)));
|
||||||
|
BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString());
|
||||||
|
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null;
|
||||||
|
|
||||||
|
return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel,
|
||||||
|
description, anvilCost, exclusiveSetTag, bedrockEnchantment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<EnchantmentComponent> readEnchantmentComponents(NbtMap effects) {
|
||||||
|
Set<EnchantmentComponent> components = new HashSet<>();
|
||||||
|
for (Map.Entry<String, Object> entry : effects.entrySet()) {
|
||||||
|
switch (entry.getKey()) {
|
||||||
|
case "minecraft:prevent_armor_change" -> components.add(EnchantmentComponent.PREVENT_ARMOR_CHANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Set.copyOf(components); // Also ensures any empty sets are consolidated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.item.enchantment;
|
||||||
|
|
||||||
|
public class EnchantmentComponent {
|
||||||
|
/**
|
||||||
|
* Singleton with no additional data
|
||||||
|
*/
|
||||||
|
public static final EnchantmentComponent PREVENT_ARMOR_CHANGE = new EnchantmentComponent();
|
||||||
|
}
|
||||||
|
|
@ -28,15 +28,13 @@ package org.geysermc.geyser.item.type;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||||
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
|
import org.geysermc.geyser.inventory.item.Potion;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
public class ArrowItem extends Item {
|
public class ArrowItem extends Item {
|
||||||
public ArrowItem(String javaIdentifier, Builder builder) {
|
public ArrowItem(String javaIdentifier, Builder builder) {
|
||||||
super(javaIdentifier, builder);
|
super(javaIdentifier, builder);
|
||||||
|
|
@ -44,13 +42,18 @@ public class ArrowItem extends Item {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||||
TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage());
|
Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage());
|
||||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||||
if (tippedArrowPotion != null) {
|
if (potion != null) {
|
||||||
itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
|
itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
|
||||||
PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Collections.emptyList());
|
PotionContents contents = potion.toComponent();
|
||||||
itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents);
|
itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents);
|
||||||
}
|
}
|
||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreDamage() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
package org.geysermc.geyser.item.type;
|
package org.geysermc.geyser.item.type;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.Style;
|
import net.kyori.adventure.text.format.Style;
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
|
@ -35,12 +36,13 @@ import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||||
import org.geysermc.geyser.inventory.item.DyeColor;
|
import org.geysermc.geyser.inventory.item.DyeColor;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||||
|
import org.geysermc.geyser.util.MinecraftKey;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||||
|
|
@ -59,9 +61,6 @@ public class BannerItem extends BlockItem {
|
||||||
*/
|
*/
|
||||||
private static final List<Pair<BannerPattern, DyeColor>> OMINOUS_BANNER_PATTERN;
|
private static final List<Pair<BannerPattern, DyeColor>> OMINOUS_BANNER_PATTERN;
|
||||||
|
|
||||||
// TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/
|
|
||||||
private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 };
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Construct what an ominous banner is supposed to look like
|
// Construct what an ominous banner is supposed to look like
|
||||||
OMINOUS_BANNER_PATTERN = List.of(
|
OMINOUS_BANNER_PATTERN = List.of(
|
||||||
|
|
@ -108,7 +107,7 @@ public class BannerItem extends BlockItem {
|
||||||
if (color != pair.right()) {
|
if (color != pair.right()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch
|
Key id = MinecraftKey.key(patternLayer.getString("pattern")); // Ouch
|
||||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id);
|
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id);
|
||||||
if (bannerPattern != pair.left()) {
|
if (bannerPattern != pair.left()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -145,8 +144,8 @@ public class BannerItem extends BlockItem {
|
||||||
} else {
|
} else {
|
||||||
List<NbtMap> patternList = new ArrayList<>(patterns.size());
|
List<NbtMap> patternList = new ArrayList<>(patterns.size());
|
||||||
for (BannerPatternLayer patternLayer : patterns) {
|
for (BannerPatternLayer patternLayer : patterns) {
|
||||||
patternLayer.getPattern().ifId(holder -> {
|
patternLayer.getPattern().ifId(id -> {
|
||||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id());
|
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(id);
|
||||||
if (bannerPattern != null) {
|
if (bannerPattern != null) {
|
||||||
NbtMap tag = NbtMap.builder()
|
NbtMap tag = NbtMap.builder()
|
||||||
.putString("Pattern", bannerPattern.getBedrockIdentifier())
|
.putString("Pattern", bannerPattern.getBedrockIdentifier())
|
||||||
|
|
@ -168,7 +167,7 @@ public class BannerItem extends BlockItem {
|
||||||
*/
|
*/
|
||||||
private static NbtMap getBedrockBannerPattern(NbtMap pattern) {
|
private static NbtMap getBedrockBannerPattern(NbtMap pattern) {
|
||||||
// ViaVersion 1.20.4 -> 1.20.5 can send without the namespace
|
// ViaVersion 1.20.4 -> 1.20.5 can send without the namespace
|
||||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern")));
|
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(MinecraftKey.key(pattern.getString("pattern")));
|
||||||
DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color"));
|
DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color"));
|
||||||
if (bannerPattern == null || dyeColor == null) {
|
if (bannerPattern == null || dyeColor == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -199,8 +198,8 @@ public class BannerItem extends BlockItem {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BannerItem(String javaIdentifier, Builder builder) {
|
public BannerItem(Builder builder, Block block, Block... otherBlocks) {
|
||||||
super(javaIdentifier, builder);
|
super(builder, block, otherBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -214,20 +213,22 @@ public class BannerItem extends BlockItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||||
|
|
||||||
if (bedrockTag.getInt("Type") == 1) {
|
if (bedrockTag.getInt("Type") == 1) {
|
||||||
// Ominous banner pattern
|
// Ominous banner pattern
|
||||||
List<BannerPatternLayer> patternLayers = new ArrayList<>();
|
List<BannerPatternLayer> patternLayers = new ArrayList<>();
|
||||||
for (int i = 0; i < ominousBannerPattern.length; i++) {
|
for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) {
|
||||||
patternLayers.add(new BannerPatternLayer(Holder.ofId(ominousBannerPattern[i]), OMINOUS_BANNER_PATTERN.get(i).right().ordinal()));
|
var pair = OMINOUS_BANNER_PATTERN.get(i);
|
||||||
|
patternLayers.add(new BannerPatternLayer(Holder.ofId(session.getRegistryCache().bannerPatterns().byValue(pair.left())),
|
||||||
|
pair.right().ordinal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
components.put(DataComponentType.BANNER_PATTERNS, patternLayers);
|
components.put(DataComponentType.BANNER_PATTERNS, patternLayers);
|
||||||
components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE);
|
components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE);
|
||||||
components.put(DataComponentType.ITEM_NAME, Component
|
components.put(DataComponentType.ITEM_NAME, Component
|
||||||
.translatable("block.minecraft.ominous_banner") // thank god this works
|
.translatable("block.minecraft.ominous_banner")
|
||||||
.style(Style.style(TextColor.color(16755200)))
|
.style(Style.style(TextColor.color(16755200)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,26 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.item.type;
|
package org.geysermc.geyser.item.type;
|
||||||
|
|
||||||
/**
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
* TODO needed?
|
|
||||||
*/
|
|
||||||
public class BlockItem extends Item {
|
public class BlockItem extends Item {
|
||||||
public BlockItem(String javaIdentifier, Builder builder) {
|
public BlockItem(Builder builder, Block block, Block... otherBlocks) {
|
||||||
|
super(block.javaIdentifier().value(), builder);
|
||||||
|
|
||||||
|
// Ensure this item can be looked up by its block(s)
|
||||||
|
registerBlock(block, this);
|
||||||
|
for (Block otherBlock : otherBlocks) {
|
||||||
|
registerBlock(otherBlock, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this constructor if the item name is not the same as its primary block
|
||||||
|
public BlockItem(String javaIdentifier, Builder builder, Block block, Block... otherBlocks) {
|
||||||
super(javaIdentifier, builder);
|
super(javaIdentifier, builder);
|
||||||
|
|
||||||
|
registerBlock(block, this);
|
||||||
|
for (Block otherBlock : otherBlocks) {
|
||||||
|
registerBlock(otherBlock, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.item.type;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||||
|
|
@ -38,8 +39,8 @@ import java.util.List;
|
||||||
|
|
||||||
public class DecoratedPotItem extends BlockItem {
|
public class DecoratedPotItem extends BlockItem {
|
||||||
|
|
||||||
public DecoratedPotItem(String javaIdentifier, Builder builder) {
|
public DecoratedPotItem(Builder builder, Block block, Block... otherBlocks) {
|
||||||
super(javaIdentifier, builder);
|
super(builder, block, otherBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.item.ArmorMaterial;
|
import org.geysermc.geyser.item.ArmorMaterial;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor;
|
|
||||||
|
|
||||||
public class DyeableArmorItem extends ArmorItem {
|
public class DyeableArmorItem extends ArmorItem {
|
||||||
public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) {
|
public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) {
|
||||||
|
|
@ -44,9 +42,6 @@ public class DyeableArmorItem extends ArmorItem {
|
||||||
|
|
||||||
// Note that this is handled as of 1.20.5 in the ItemColors class.
|
// Note that this is handled as of 1.20.5 in the ItemColors class.
|
||||||
// But horse leather armor and body leather armor are now both armor items. So it works!
|
// But horse leather armor and body leather armor are now both armor items. So it works!
|
||||||
DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR);
|
translateDyedColor(components, builder);
|
||||||
if (dyedItemColor != null) {
|
|
||||||
builder.putInt("customColor", dyedItemColor.getRgb());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtType;
|
import org.cloudburstmc.nbt.NbtType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||||
|
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||||
|
|
@ -69,8 +70,8 @@ public class EnchantedBookItem extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||||
|
|
||||||
List<NbtMap> enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND);
|
List<NbtMap> enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND);
|
||||||
if (enchantmentTag != null) {
|
if (enchantmentTag != null) {
|
||||||
|
|
@ -78,11 +79,16 @@ public class EnchantedBookItem extends Item {
|
||||||
for (NbtMap bedrockEnchantment : enchantmentTag) {
|
for (NbtMap bedrockEnchantment : enchantmentTag) {
|
||||||
short bedrockId = bedrockEnchantment.getShort("id");
|
short bedrockId = bedrockEnchantment.getShort("id");
|
||||||
|
|
||||||
Enchantment enchantment = Enchantment.getByBedrockId(bedrockId);
|
BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId);
|
||||||
if (enchantment != null) {
|
if (enchantment != null) {
|
||||||
int level = bedrockEnchantment.getShort("lvl", (short) 1);
|
List<Enchantment> enchantments = session.getRegistryCache().enchantments().values();
|
||||||
// TODO
|
for (int i = 0; i < enchantments.size(); i++) {
|
||||||
javaEnchantments.put(Enchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level);
|
if (enchantments.get(i).bedrockEnchantment() == enchantment) {
|
||||||
|
int level = bedrockEnchantment.getShort("lvl", (short) 1);
|
||||||
|
javaEnchantments.put(i, level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
|
GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ public class FireworkRocketItem extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||||
|
|
||||||
NbtMap fireworksTag = bedrockTag.getCompound("Fireworks");
|
NbtMap fireworksTag = bedrockTag.getCompound("Fireworks");
|
||||||
if (!fireworksTag.isEmpty()) {
|
if (!fireworksTag.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ public class FireworkStarItem extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||||
|
|
||||||
NbtMap explosion = bedrockTag.getCompound("FireworksItem");
|
NbtMap explosion = bedrockTag.getCompound("FireworksItem");
|
||||||
if (!explosion.isEmpty()) {
|
if (!explosion.isEmpty()) {
|
||||||
|
|
@ -90,4 +90,9 @@ public class FireworkStarItem extends Item {
|
||||||
components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion);
|
components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreDamage() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,4 +62,9 @@ public class GoatHornItem extends Item {
|
||||||
|
|
||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreDamage() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue