Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-10-05 09:20:07 +02:00
Merge remote-tracking branch 'refs/remotes/upstream/master' into customitemapi
Dieser Commit ist enthalten in:
Commit
ac4d543069
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
|
- name: Archive Artifacts
|
||||||
# See https://github.com/actions/checkout/commits
|
uses: GeyserMC/actions/upload-multi-artifact@master
|
||||||
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
|
|
||||||
# See https://github.com/gradle/actions/commits
|
|
||||||
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
Normale Datei
33
.github/workflows/dispatch-preview.yml
vendored
Normale Datei
@ -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/
|
|
14
.github/workflows/pull-request.yml
vendored
14
.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 }}
|
@ -1,6 +1,7 @@
|
|||||||
<component name="CopyrightManager">
|
<component name="CopyrightManager">
|
||||||
<copyright>
|
<copyright>
|
||||||
<option name="notice" value="Copyright (c) 2019-&#36;today.year 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" />
|
<option name="allowReplaceRegexp" value="Copyright" />
|
||||||
|
<option name="notice" value="Copyright (c) &#36;originalComment.match("Copyright \(c\) (\d+)", 1, "-")&#36;today.year 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" />
|
||||||
<option name="myName" value="Geyser" />
|
<option name="myName" value="Geyser" />
|
||||||
</copyright>
|
</copyright>
|
||||||
</component>
|
</component>
|
@ -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;
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-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.event.bedrock;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
|
import org.geysermc.geyser.api.skin.Cape;
|
||||||
|
import org.geysermc.geyser.api.skin.Skin;
|
||||||
|
import org.geysermc.geyser.api.skin.SkinData;
|
||||||
|
import org.geysermc.geyser.api.skin.SkinGeometry;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a skin is applied to a player.
|
||||||
|
* <p>
|
||||||
|
* Won't be called when a fake player is spawned for a player skull.
|
||||||
|
*/
|
||||||
|
public abstract class SessionSkinApplyEvent extends ConnectionEvent {
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
private final UUID uuid;
|
||||||
|
private final boolean slim;
|
||||||
|
private final boolean bedrock;
|
||||||
|
private final SkinData originalSkinData;
|
||||||
|
|
||||||
|
public SessionSkinApplyEvent(@NonNull GeyserConnection connection, String username, UUID uuid, boolean slim, boolean bedrock, SkinData skinData) {
|
||||||
|
super(connection);
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.slim = slim;
|
||||||
|
this.bedrock = bedrock;
|
||||||
|
this.originalSkinData = skinData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the player.
|
||||||
|
*
|
||||||
|
* @return the username of the player
|
||||||
|
*/
|
||||||
|
public @NonNull String username() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UUID of the player.
|
||||||
|
*
|
||||||
|
* @return the UUID of the player
|
||||||
|
*/
|
||||||
|
public @NonNull UUID uuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the player is using a slim model.
|
||||||
|
*
|
||||||
|
* @return if the player is using a slim model
|
||||||
|
*/
|
||||||
|
public boolean slim() {
|
||||||
|
return slim;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the player is a Bedrock player.
|
||||||
|
*
|
||||||
|
* @return if the player is a Bedrock player
|
||||||
|
*/
|
||||||
|
public boolean bedrock() {
|
||||||
|
return bedrock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original skin data of the player.
|
||||||
|
*
|
||||||
|
* @return the original skin data of the player
|
||||||
|
*/
|
||||||
|
public @NonNull SkinData originalSkin() {
|
||||||
|
return originalSkinData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The skin data of the player.
|
||||||
|
*
|
||||||
|
* @return the current skin data of the player
|
||||||
|
*/
|
||||||
|
public abstract @NonNull SkinData skinData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the skin of the player.
|
||||||
|
*
|
||||||
|
* @param newSkin the new skin
|
||||||
|
*/
|
||||||
|
public abstract void skin(@NonNull Skin newSkin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the cape of the player.
|
||||||
|
*
|
||||||
|
* @param newCape the new cape
|
||||||
|
*/
|
||||||
|
public abstract void cape(@NonNull Cape newCape);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the geometry of the player.
|
||||||
|
*
|
||||||
|
* @param newGeometry the new geometry
|
||||||
|
*/
|
||||||
|
public abstract void geometry(@NonNull SkinGeometry newGeometry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the geometry of the player.
|
||||||
|
* <p>
|
||||||
|
* Constructs a generic {@link SkinGeometry} object with the given data.
|
||||||
|
*
|
||||||
|
* @param geometryName the name of the geometry
|
||||||
|
* @param geometryData the data of the geometry
|
||||||
|
*/
|
||||||
|
public void geometry(@NonNull String geometryName, @NonNull String geometryData) {
|
||||||
|
geometry(new SkinGeometry("{\"geometry\" :{\"default\" :\"" + geometryName + "\"}}", geometryData));
|
||||||
|
}
|
||||||
|
}
|
@ -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,18 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.skin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains useful collections for use in Geyser.
|
* Represents a cape.
|
||||||
* <p>
|
*
|
||||||
* 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
|
* @param textureUrl The URL of the cape texture
|
||||||
* 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)}
|
* @param capeId The ID of the cape
|
||||||
* and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map
|
* @param capeData The raw cape image data in ARGB format
|
||||||
* size and its "start" integer.
|
* @param failed If the cape failed to load, this is for things like fallback capes
|
||||||
*/
|
*/
|
||||||
package org.geysermc.geyser.util.collection;
|
public record Cape(String textureUrl, String capeId, byte[] capeData, boolean failed) {
|
||||||
|
public Cape(String textureUrl, String capeId, byte[] capeData) {
|
||||||
|
this(textureUrl, capeId, capeData, false);
|
||||||
|
}
|
||||||
|
}
|
@ -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,18 +23,17 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.level.block;
|
package org.geysermc.geyser.api.skin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This stores all values of double chests that are part of the Java block state.
|
* Represents a skin.
|
||||||
*
|
*
|
||||||
* @param isFacingEast If true, then chest is facing east/west; if false, south/north
|
* @param textureUrl The URL/ID of the skin texture
|
||||||
* @param isDirectionPositive If true, direction is positive (east/south); if false, direction is negative (west/north)
|
* @param skinData The raw skin image data in ARGB
|
||||||
* @param isLeft If true, chest is the left of a pair; if false, chest is the right of a pair.
|
* @param failed If the skin failed to load, this is for things like fallback skins
|
||||||
*/
|
*/
|
||||||
public record DoubleChestValue(
|
public record Skin(String textureUrl, byte[] skinData, boolean failed) {
|
||||||
boolean isFacingEast,
|
public Skin(String textureUrl, byte[] skinData) {
|
||||||
boolean isDirectionPositive,
|
this(textureUrl, skinData, false);
|
||||||
boolean isLeft) {
|
}
|
||||||
|
|
||||||
}
|
}
|
32
api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
Normale Datei
32
api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
Normale Datei
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.skin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a full package of {@link Skin}, {@link Cape}, and {@link SkinGeometry}.
|
||||||
|
*/
|
||||||
|
public record SkinData(Skin skin, Cape cape, SkinGeometry geometry) {
|
||||||
|
}
|
48
api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java
Normale Datei
48
api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java
Normale Datei
@ -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.api.skin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents geometry of a skin.
|
||||||
|
*
|
||||||
|
* @param geometryName The name of the geometry (JSON)
|
||||||
|
* @param geometryData The geometry data (JSON)
|
||||||
|
*/
|
||||||
|
public record SkinGeometry(String geometryName, String geometryData) {
|
||||||
|
|
||||||
|
public static SkinGeometry WIDE = getLegacy(false);
|
||||||
|
public static SkinGeometry SLIM = getLegacy(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate generic geometry
|
||||||
|
*
|
||||||
|
* @param isSlim if true, it will be the slimmer alex model
|
||||||
|
* @return The generic geometry object
|
||||||
|
*/
|
||||||
|
private static SkinGeometry getLegacy(boolean isSlim) {
|
||||||
|
return new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.custom" + (isSlim ? "Slim" : "") + "\"}}", "");
|
||||||
|
}
|
||||||
|
}
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,9 @@ dependencies {
|
|||||||
|
|
||||||
// Let's shade in our own api
|
// Let's shade in our own api
|
||||||
shadow(projects.api) { isTransitive = false }
|
shadow(projects.api) { isTransitive = false }
|
||||||
shadow(projects.common) { isTransitive = false }
|
|
||||||
|
// cannot be shaded, since neoforge will complain if floodgate-neoforge tries to provide this
|
||||||
|
include(projects.common)
|
||||||
|
|
||||||
// Include all transitive deps of core via JiJ
|
// Include all transitive deps of core via JiJ
|
||||||
includeTransitive(projects.core)
|
includeTransitive(projects.core)
|
||||||
@ -53,4 +55,5 @@ tasks {
|
|||||||
|
|
||||||
modrinth {
|
modrinth {
|
||||||
loaders.add("neoforge")
|
loaders.add("neoforge")
|
||||||
|
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||||
}
|
}
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.platform.neoforge;
|
|||||||
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.neoforged.fml.ModContainer;
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
import net.neoforged.fml.loading.FMLLoader;
|
import net.neoforged.fml.loading.FMLLoader;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
@ -43,8 +44,8 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
|||||||
|
|
||||||
private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
|
private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
|
||||||
|
|
||||||
public GeyserNeoForgeBootstrap() {
|
public GeyserNeoForgeBootstrap(ModContainer container) {
|
||||||
super(new GeyserNeoForgePlatform());
|
super(new GeyserNeoForgePlatform(container));
|
||||||
|
|
||||||
if (isServer()) {
|
if (isServer()) {
|
||||||
// Set as an event so we can get the proper IP and port if needed
|
// Set as an event so we can get the proper IP and port if needed
|
||||||
|
@ -26,20 +26,29 @@
|
|||||||
package org.geysermc.geyser.platform.neoforge;
|
package org.geysermc.geyser.platform.neoforge;
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.neoforged.fml.ModContainer;
|
||||||
|
import net.neoforged.fml.ModList;
|
||||||
import net.neoforged.fml.loading.FMLPaths;
|
import net.neoforged.fml.loading.FMLPaths;
|
||||||
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.api.util.PlatformType;
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public class GeyserNeoForgePlatform implements GeyserModPlatform {
|
public class GeyserNeoForgePlatform implements GeyserModPlatform {
|
||||||
|
|
||||||
|
private final ModContainer container;
|
||||||
|
|
||||||
|
public GeyserNeoForgePlatform(ModContainer container) {
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull PlatformType platformType() {
|
public @NonNull PlatformType platformType() {
|
||||||
return PlatformType.NEOFORGE;
|
return PlatformType.NEOFORGE;
|
||||||
@ -62,11 +71,21 @@ public class GeyserNeoForgePlatform implements GeyserModPlatform {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
|
public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
|
||||||
return false; // No Floodgate mod for NeoForge yet
|
if (ModList.get().isLoaded("floodgate")) {
|
||||||
|
Path floodgateDataFolder = FMLPaths.CONFIGDIR.get().resolve("floodgate");
|
||||||
|
bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable InputStream resolveResource(@NonNull String resource) {
|
public @Nullable InputStream resolveResource(@NonNull String resource) {
|
||||||
return GeyserBootstrap.class.getClassLoader().getResourceAsStream(resource);
|
try {
|
||||||
|
Path path = container.getModInfo().getOwningFile().getFile().findResource(resource);
|
||||||
|
return Files.newInputStream(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -70,3 +70,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||||||
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
Normale Datei
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normale Datei
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
* Copyright (c) 2019-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
|
||||||
@ -72,8 +72,10 @@ public interface GeyserConfiguration {
|
|||||||
|
|
||||||
boolean isDebugMode();
|
boolean isDebugMode();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
boolean isAllowThirdPartyCapes();
|
boolean isAllowThirdPartyCapes();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
boolean isAllowThirdPartyEars();
|
boolean isAllowThirdPartyEars();
|
||||||
|
|
||||||
String getShowCooldown();
|
String getShowCooldown();
|
||||||
|
@ -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;
|
||||||
@ -235,7 +241,7 @@ public final class EntityDefinitions {
|
|||||||
.addTranslator(MetadataType.BOOLEAN,
|
.addTranslator(MetadataType.BOOLEAN,
|
||||||
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
|
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
|
||||||
.build();
|
.build();
|
||||||
EXPERIENCE_ORB = EntityDefinition.<ExpOrbEntity>inherited(null, entityBase)
|
EXPERIENCE_ORB = EntityDefinition.inherited(ExpOrbEntity::new, entityBase)
|
||||||
.type(EntityType.EXPERIENCE_ORB)
|
.type(EntityType.EXPERIENCE_ORB)
|
||||||
.identifier("minecraft:xp_orb")
|
.identifier("minecraft:xp_orb")
|
||||||
.build();
|
.build();
|
||||||
@ -297,6 +303,7 @@ public final class EntityDefinitions {
|
|||||||
TNT = EntityDefinition.inherited(TNTEntity::new, entityBase)
|
TNT = EntityDefinition.inherited(TNTEntity::new, entityBase)
|
||||||
.type(EntityType.TNT)
|
.type(EntityType.TNT)
|
||||||
.heightAndWidth(0.98f)
|
.heightAndWidth(0.98f)
|
||||||
|
.offset(0.49f)
|
||||||
.addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
|
.addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -374,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"
|
||||||
@ -502,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;
|
||||||
@ -59,6 +60,9 @@ import java.util.*;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class Entity implements GeyserEntity {
|
public class Entity implements GeyserEntity {
|
||||||
|
|
||||||
|
private static final boolean PRINT_ENTITY_SPAWN_DEBUG = Boolean.parseBoolean(System.getProperty("Geyser.PrintEntitySpawnDebug", "false"));
|
||||||
|
|
||||||
protected final GeyserSession session;
|
protected final GeyserSession session;
|
||||||
|
|
||||||
protected int entityId;
|
protected int entityId;
|
||||||
@ -134,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());
|
||||||
@ -181,7 +185,7 @@ public class Entity implements GeyserEntity {
|
|||||||
|
|
||||||
flagsDirty = false;
|
flagsDirty = false;
|
||||||
|
|
||||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
if (session.getGeyser().getConfig().isDebugMode() && PRINT_ENTITY_SPAWN_DEBUG) {
|
||||||
EntityType type = definition.entityType();
|
EntityType type = definition.entityType();
|
||||||
String name = type != null ? type.name() : getClass().getSimpleName();
|
String name = type != null ? type.name() : getClass().getSimpleName();
|
||||||
session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
@ -361,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());
|
||||||
@ -554,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,11 +27,18 @@ 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.EntityDefinitions;
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ExpOrbEntity extends Entity {
|
public class ExpOrbEntity extends Entity {
|
||||||
|
|
||||||
|
public ExpOrbEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> entityDefinition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
this(session, 1, entityId, geyserId, position);
|
||||||
|
}
|
||||||
|
|
||||||
public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) {
|
public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) {
|
||||||
super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0);
|
super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
44
core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java
Normale Datei
44
core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java
Normale Datei
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I can haz lead
|
||||||
|
* (The item, not the mineral)
|
||||||
|
*/
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,17 @@ public class TNTEntity extends Entity implements Tickable {
|
|||||||
private int currentTick;
|
private int currentTick;
|
||||||
|
|
||||||
public TNTEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
public TNTEntity(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);
|
super(session, entityId, geyserId, uuid, definition, position.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
|
||||||
|
super.moveRelative(relX, relY + definition.offset(), relZ, yaw, pitch, isOnGround);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||||
|
super.moveAbsolute(position.add(Vector3f.from(0, definition.offset(), 0)), yaw, pitch, headYaw, isOnGround, teleported);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFuseLength(IntEntityMetadata entityMetadata) {
|
public void setFuseLength(IntEntityMetadata entityMetadata) {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ 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.data.entity.EntityLinkData;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.*;
|
import org.cloudburstmc.protocol.bedrock.packet.*;
|
||||||
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
||||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
@ -166,6 +167,31 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
|
|||||||
session.sendUpstreamPacket(addPlayerPacket);
|
session.sendUpstreamPacket(addPlayerPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void despawnEntity() {
|
||||||
|
super.despawnEntity();
|
||||||
|
|
||||||
|
// Since we re-use player entities: Clear flags, held item, etc
|
||||||
|
this.resetMetadata();
|
||||||
|
this.hand = ItemData.AIR;
|
||||||
|
this.offhand = ItemData.AIR;
|
||||||
|
this.boots = ItemData.AIR;
|
||||||
|
this.leggings = ItemData.AIR;
|
||||||
|
this.chestplate = ItemData.AIR;
|
||||||
|
this.helmet = ItemData.AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetMetadata() {
|
||||||
|
// Reset all metadata to their default values
|
||||||
|
// This is used when a player respawns
|
||||||
|
this.flags.clear();
|
||||||
|
this.initializeMetadata();
|
||||||
|
|
||||||
|
// Explicitly reset all metadata not handled by initializeMetadata
|
||||||
|
setParrot(null, true);
|
||||||
|
setParrot(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
public void sendPlayer() {
|
public void sendPlayer() {
|
||||||
if (session.getEntityCache().getPlayerEntity(uuid) == null)
|
if (session.getEntityCache().getPlayerEntity(uuid) == null)
|
||||||
return;
|
return;
|
||||||
|
@ -35,6 +35,7 @@ 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.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.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.AttributeUtils;
|
import org.geysermc.geyser.util.AttributeUtils;
|
||||||
import org.geysermc.geyser.util.DimensionUtils;
|
import org.geysermc.geyser.util.DimensionUtils;
|
||||||
@ -60,16 +61,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();
|
||||||
|
|
||||||
public SessionPlayerEntity(GeyserSession session) {
|
public SessionPlayerEntity(GeyserSession session) {
|
||||||
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
||||||
|
|
||||||
@ -120,9 +119,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +147,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() {
|
||||||
@ -167,7 +163,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);
|
||||||
@ -199,21 +201,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) {
|
||||||
@ -226,17 +213,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;
|
||||||
}
|
}
|
||||||
@ -244,7 +220,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);
|
||||||
@ -264,19 +240,13 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
super.setAbsorptionHearts(entityMetadata);
|
super.setAbsorptionHearts(entityMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void resetMetadata() {
|
public void resetMetadata() {
|
||||||
// Reset all metadata to their default values
|
super.resetMetadata();
|
||||||
// This is used when a player respawns
|
|
||||||
this.flags.clear();
|
|
||||||
this.initializeMetadata();
|
|
||||||
|
|
||||||
// Reset air
|
// Reset air
|
||||||
this.resetAir();
|
this.resetAir();
|
||||||
|
|
||||||
// Explicitly reset all metadata not handled by initializeMetadata
|
|
||||||
setParrot(null, true);
|
|
||||||
setParrot(null, false);
|
|
||||||
|
|
||||||
// Absorption is metadata in java edition
|
// Absorption is metadata in java edition
|
||||||
attributes.remove(GeyserAttributeType.ABSORPTION);
|
attributes.remove(GeyserAttributeType.ABSORPTION);
|
||||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||||
|
@ -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,57 +34,68 @@ 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() {
|
||||||
@ -106,4 +117,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;
|
||||||
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren