mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Merge remote-tracking branch 'refs/remotes/upstream/master' into suppress-0.0.0.0
# Conflicts: # core/src/main/java/org/geysermc/geyser/GeyserImpl.java
This commit is contained in:
commit
30ae001413
887 changed files with 44749 additions and 40134 deletions
14
.editorconfig
Normal file
14
.editorconfig
Normal file
|
@ -0,0 +1,14 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
max_line_length = off
|
||||
|
||||
[*.java]
|
||||
ij_java_class_count_to_use_import_on_demand = 9999
|
||||
ij_java_doc_align_exception_comments = false
|
||||
ij_java_doc_align_param_comments = false
|
47
.github/workflows/build-remote.yml
vendored
Normal file
47
.github/workflows/build-remote.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
name: Build Remote
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
repository:
|
||||
required: true
|
||||
description: 'The repo of the remote'
|
||||
type: string
|
||||
ref:
|
||||
required: true
|
||||
description: 'The ref of the remote'
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set Build Number
|
||||
run: |
|
||||
echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: GeyserMC/actions/setup-gradle-composite@master
|
||||
with:
|
||||
checkout_repository: ${{ inputs.repository }}
|
||||
checkout_ref: ${{ inputs.ref }}
|
||||
setup-java_java-version: 21
|
||||
setup-gradle_cache-read-only: true
|
||||
|
||||
- name: Build Geyser
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Archive Artifacts
|
||||
uses: GeyserMC/actions/upload-multi-artifact@master
|
||||
if: success()
|
||||
with:
|
||||
artifacts: |
|
||||
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
165
.github/workflows/build.yml
vendored
165
.github/workflows/build.yml
vendored
|
@ -3,127 +3,118 @@ name: Build
|
|||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'gh-readonly-queue/**'
|
||||
paths-ignore:
|
||||
- '.github/ISSUE_TEMPLATE/*.yml'
|
||||
- '.github/actions/pullrequest.yml'
|
||||
- '.idea/copyright/*.xml'
|
||||
- '.github/workflows/build-remote.yml'
|
||||
- '.github/workflows/preview.yml'
|
||||
- '.github/workflows/pull-request.yml'
|
||||
- '.idea/copyright/*.xml'
|
||||
- '.gitignore'
|
||||
- 'CONTRIBUTING.md'
|
||||
- 'LICENSE'
|
||||
- 'Jenkinsfile '
|
||||
- 'README.md'
|
||||
- 'licenseheader.txt'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository and submodules
|
||||
# See https://github.com/actions/checkout/commits
|
||||
uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
|
||||
- name: Get Release Info
|
||||
id: release-info
|
||||
uses: GeyserMC/actions/previous-release@master
|
||||
with:
|
||||
submodules: recursive
|
||||
data: ${{ vars.RELEASEACTION_PREVRELEASE }}
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
# See https://github.com/gradle/wrapper-validation-action/commits
|
||||
uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
|
||||
- name: Setup Gradle
|
||||
uses: GeyserMC/actions/setup-gradle-composite@master
|
||||
with:
|
||||
setup-java_java-version: 21
|
||||
|
||||
# See https://github.com/actions/setup-java/commits
|
||||
- uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Build Geyser
|
||||
run: ./gradlew build
|
||||
env:
|
||||
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||
|
||||
- name: Build
|
||||
# See https://github.com/gradle/gradle-build-action/commits
|
||||
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
- name: Archive Artifacts
|
||||
uses: GeyserMC/actions/upload-multi-artifact@master
|
||||
if: success()
|
||||
with:
|
||||
name: Geyser Fabric
|
||||
path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
||||
if-no-files-found: error
|
||||
- name: Archive artifacts (Geyser Standalone)
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
if: success()
|
||||
with:
|
||||
name: Geyser Velocity
|
||||
path: bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
if-no-files-found: error
|
||||
artifacts: |
|
||||
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||
|
||||
- name: Publish to Maven Repository
|
||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||
run: ./gradlew publish
|
||||
env:
|
||||
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
|
||||
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
|
||||
|
||||
- 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
|
||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||
uses: GeyserMC/actions/release@master
|
||||
id: metadata
|
||||
with:
|
||||
arguments: publish
|
||||
appID: ${{ secrets.RELEASE_APP_ID }}
|
||||
appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
|
||||
files: |
|
||||
bungeecord:bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||
fabric:bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||
neoforge:bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||
spigot:bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||
standalone:bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||
velocity:bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||
releaseEnabled: false
|
||||
saveMetadata: true
|
||||
releaseProject: 'geyser'
|
||||
releaseVersion: ${{ steps.get-version.outputs.VERSION }}
|
||||
|
||||
- name: Publish to Downloads API
|
||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||
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
|
||||
# Set the project
|
||||
project=geyser
|
||||
# Get the version from gradle.properties
|
||||
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
||||
# Create the build folder
|
||||
ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/"
|
||||
# Copy over artifacts
|
||||
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/
|
||||
# Run the build script
|
||||
# Push the metadata
|
||||
echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
|
||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
|
||||
uses: GeyserMC/actions/upload-release@master
|
||||
with:
|
||||
username: ${{ vars.DOWNLOADS_USERNAME }}
|
||||
privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
|
||||
host: ${{ secrets.DOWNLOADS_SERVER_IP }}
|
||||
files: |
|
||||
bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||
bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
|
||||
bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
|
||||
bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||
bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||
bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||
changelog: ${{ steps.metadata.outputs.body }}
|
||||
|
||||
- name: Publish to Modrinth
|
||||
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||
env:
|
||||
CHANGELOG: ${{ steps.metadata.outputs.body }}
|
||||
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
with:
|
||||
arguments: fabric:modrinth
|
||||
gradle-home-cache-cleanup: true
|
||||
|
||||
run: ./gradlew modrinth
|
||||
|
||||
- name: Notify Discord
|
||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||
# See https://github.com/Tim203/actions-git-discord-webhook/commits
|
||||
uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
|
||||
uses: GeyserMC/actions/notify-discord@master
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
discordWebhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
status: ${{ job.status }}
|
||||
body: ${{ steps.metadata.outputs.body }}
|
||||
includeDownloads: ${{ github.ref_name == 'master' }}
|
||||
|
|
33
.github/workflows/dispatch-preview.yml
vendored
Normal file
33
.github/workflows/dispatch-preview.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: Dispatch Preview
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
runId:
|
||||
required: true
|
||||
description: 'ID of the action to pull artifacts from'
|
||||
build:
|
||||
required: true
|
||||
description: 'Build number for the release'
|
||||
version:
|
||||
required: true
|
||||
description: 'Version under which to upload to the Downloads API'
|
||||
|
||||
jobs:
|
||||
dispatch-preview:
|
||||
# Allow access to secrets if we are uploading a preview
|
||||
secrets: inherit
|
||||
uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
|
||||
with:
|
||||
build: ${{ inputs.build }}
|
||||
version: ${{ inputs.version }}
|
||||
files: |
|
||||
bungeecord:Geyser-BungeeCord.jar
|
||||
fabric:Geyser-Fabric.jar
|
||||
neoforge:Geyser-NeoForge.jar
|
||||
spigot:Geyser-Spigot.jar
|
||||
standalone:Geyser-Standalone.jar
|
||||
velocity:Geyser-Velocity.jar
|
||||
viaproxy:Geyser-ViaProxy.jar
|
||||
project: geyserpreview
|
||||
runId: ${{ inputs.runId }}
|
34
.github/workflows/pull-request.yml
vendored
Normal file
34
.github/workflows/pull-request.yml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Process Pull Request
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Forbid access to secrets nor GH Token perms while building the PR
|
||||
permissions: {}
|
||||
secrets: {}
|
||||
uses: GeyserMC/Geyser/.github/workflows/build-remote.yml@master
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
preview:
|
||||
needs: [build]
|
||||
if: >-
|
||||
contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
|
||||
# Allow access to secrets if we are uploading a preview
|
||||
secrets: inherit
|
||||
uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
|
||||
with:
|
||||
build: ${{ github.run_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 }}
|
98
.github/workflows/pullrequest.yml
vendored
98
.github/workflows/pullrequest.yml
vendored
|
@ -1,98 +0,0 @@
|
|||
name: Build Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/ISSUE_TEMPLATE/*.yml'
|
||||
- '.idea/copyright/*.xml'
|
||||
- '.gitignore'
|
||||
- 'CONTRIBUTING.md'
|
||||
- 'LICENSE'
|
||||
- 'Jenkinsfile '
|
||||
- 'README.md'
|
||||
- 'licenseheader.txt'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up JDK 17
|
||||
# See https://github.com/actions/setup-java/commits
|
||||
uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Check if the author has forked the API repo
|
||||
# See https://github.com/Kas-tle/find-forks-action/commits
|
||||
uses: Kas-tle/find-forks-action@1b5447d1e3c7a8ed79583dd817cc5399686eed3a
|
||||
id: find_forks
|
||||
with:
|
||||
owner: GeyserMC
|
||||
repo: api
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Use author's API repo if it exists
|
||||
if: ${{ steps.find_forks.outputs.target_branch_found == 'true' }}
|
||||
env:
|
||||
API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
|
||||
API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api
|
||||
cd api
|
||||
./gradlew publishToMavenLocal
|
||||
|
||||
- name: Checkout repository and submodules
|
||||
# See https://github.com/actions/checkout/commits
|
||||
uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
|
||||
with:
|
||||
submodules: recursive
|
||||
path: geyser
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
# See https://github.com/gradle/wrapper-validation-action/commits
|
||||
uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
|
||||
|
||||
- name: Build Geyser
|
||||
# See https://github.com/gradle/gradle-build-action/commits
|
||||
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||
with:
|
||||
arguments: build
|
||||
build-root-directory: geyser
|
||||
|
||||
- name: Archive artifacts (Geyser Fabric)
|
||||
# See https://github.com/actions/upload-artifact/commits
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
if: success()
|
||||
with:
|
||||
name: Geyser Fabric
|
||||
path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
||||
if-no-files-found: error
|
||||
- name: Archive artifacts (Geyser Standalone)
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||
if: success()
|
||||
with:
|
||||
name: Geyser Velocity
|
||||
path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar
|
||||
if-no-files-found: error
|
3
.idea/copyright/Geyser.xml
generated
3
.idea/copyright/Geyser.xml
generated
|
@ -1,6 +1,7 @@
|
|||
<component name="CopyrightManager">
|
||||
<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" />
|
||||
</copyright>
|
||||
</component>
|
|
@ -19,32 +19,28 @@ public class LongClassName {
|
|||
public int nameWithMultipleWords = 0;
|
||||
|
||||
/**
|
||||
* Javadoc comment to explain what a function does.
|
||||
*/
|
||||
* Javadoc comment to explain what a function does.
|
||||
*/
|
||||
@RandomAnnotation(stuff = true, moreStuff = "might exist")
|
||||
public void applyStuff() {
|
||||
Variable variable = new Variable();
|
||||
Variable otherVariable = new Variable();
|
||||
|
||||
if (condition) {
|
||||
// Do stuff.
|
||||
// Do stuff.
|
||||
} else if (anotherCondition) {
|
||||
// Do something else.
|
||||
// Do something else.
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 0:
|
||||
stuff();
|
||||
break;
|
||||
case 1:
|
||||
differentStuff();
|
||||
break;
|
||||
case 0 -> stuff();
|
||||
case 1 -> differentStuff();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Make sure to comment your code where possible.
|
||||
Make sure to comment your code where possible. To mark nullable methods, use `@Nullable` (and subsequently, `@NonNull`) from the `org.checkerframework.checker.nullness.qual` package.
|
||||
|
||||
The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`.
|
||||
|
||||
|
|
28
Jenkinsfile
vendored
28
Jenkinsfile
vendored
|
@ -1,28 +0,0 @@
|
|||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
gradle 'Gradle 7'
|
||||
jdk 'Java 17'
|
||||
}
|
||||
options {
|
||||
buildDiscarder(logRotator(artifactNumToKeepStr: '20'))
|
||||
}
|
||||
stages {
|
||||
stage ('Build') {
|
||||
steps {
|
||||
sh 'git submodule update --init --recursive'
|
||||
rtGradleRun(
|
||||
usesPlugin: true,
|
||||
tool: 'Gradle 7',
|
||||
buildFile: 'build.gradle.kts',
|
||||
tasks: 'clean build',
|
||||
)
|
||||
}
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'bootstrap/**/build/libs/Geyser-*.jar', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (c) 2019-2023 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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
20
README.md
20
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](LICENSE)
|
||||
[](https://discord.gg/geysermc)
|
||||
[](https://translate.geysermc.org/)
|
||||
[](https://translate.geysermc.org/)
|
||||
|
||||
Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform.
|
||||
|
||||
|
@ -14,16 +14,15 @@ 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!
|
||||
|
||||
### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.31 and Minecraft Java 1.20/1.20.1.
|
||||
## Supported Versions
|
||||
Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.3 and Minecraft Java Server 1.21. For more info please see [here](https://geysermc.org/wiki/geyser/supported-versions/).
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
|
||||
|
||||
[](https://www.youtube.com/watch?v=U7dZZ8w7Gi4)
|
||||
Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser.
|
||||
|
||||
## Links:
|
||||
- Website: https://geysermc.org
|
||||
- Docs: https://wiki.geysermc.org/geyser/
|
||||
- Docs: https://geysermc.org/wiki/geyser/
|
||||
- Download: https://geysermc.org/download
|
||||
- Discord: https://discord.gg/geysermc
|
||||
- Donate: https://opencollective.com/geysermc
|
||||
|
@ -32,10 +31,9 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge
|
|||
## What's Left to be Added/Fixed
|
||||
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
|
||||
- Some Entity Flags
|
||||
- Structure block UI
|
||||
|
||||
## What can't be fixed
|
||||
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page.
|
||||
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://geysermc.org/wiki/geyser/current-limitations/) page.
|
||||
|
||||
## Compiling
|
||||
1. Clone the repo to your computer
|
||||
|
@ -43,12 +41,12 @@ There are a few things Geyser is unable to support due to various differences be
|
|||
3. Run `gradlew build` and locate to `bootstrap/build` folder.
|
||||
|
||||
## Contributing
|
||||
Any contributions are appreciated. Please feel free to reach out to us on [Discord](http://discord.geysermc.org/) if
|
||||
Any contributions are appreciated. Please feel free to reach out to us on [Discord](https://discord.gg/geysermc) if
|
||||
you're interested in helping out with Geyser.
|
||||
|
||||
## Libraries Used:
|
||||
- [Adventure Text Library](https://github.com/KyoriPowered/adventure)
|
||||
- [NukkitX Bedrock Protocol Library](https://github.com/NukkitX/Protocol)
|
||||
- [Steveice10's Java Protocol Library](https://github.com/Steveice10/MCProtocolLib)
|
||||
- [CloudburstMC Bedrock Protocol Library](https://github.com/CloudburstMC/Protocol)
|
||||
- [GeyserMC's Java Protocol Library](https://github.com/GeyserMC/MCProtocolLib)
|
||||
- [TerminalConsoleAppender](https://github.com/Minecrell/TerminalConsoleAppender)
|
||||
- [Simple Logging Facade for Java (slf4j)](https://github.com/qos-ch/slf4j)
|
||||
|
|
|
@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
|||
import javax.lang.model.SourceVersion;
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_16)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
public class BlockEntityProcessor extends ClassProcessor {
|
||||
public BlockEntityProcessor() {
|
||||
super("org.geysermc.geyser.translator.level.block.entity.BlockEntity");
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.processor;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
|
@ -159,7 +161,7 @@ public class ClassProcessor extends AbstractProcessor {
|
|||
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Completed processing for " + this.annotationClassName);
|
||||
}
|
||||
|
||||
private BufferedReader createReader() throws IOException {
|
||||
private @Nullable BufferedReader createReader() throws IOException {
|
||||
if (this.outputPath != null) {
|
||||
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Reading existing " + this.annotationClassName + " list from " + this.outputPath);
|
||||
return Files.newBufferedReader(this.outputPath);
|
||||
|
|
|
@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
|||
import javax.lang.model.SourceVersion;
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_16)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
public class CollisionRemapperProcessor extends ClassProcessor {
|
||||
public CollisionRemapperProcessor() {
|
||||
super("org.geysermc.geyser.translator.collision.CollisionRemapper");
|
||||
|
|
|
@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
|||
import javax.lang.model.SourceVersion;
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_16)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
public class PacketTranslatorProcessor extends ClassProcessor {
|
||||
public PacketTranslatorProcessor() {
|
||||
super("org.geysermc.geyser.translator.protocol.Translator");
|
||||
|
|
|
@ -30,7 +30,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
|||
import javax.lang.model.SourceVersion;
|
||||
|
||||
@SupportedAnnotationTypes("*")
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_16)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
public class SoundHandlerProcessor extends ClassProcessor {
|
||||
public SoundHandlerProcessor() {
|
||||
super("org.geysermc.geyser.translator.sound.SoundTranslator");
|
||||
|
|
|
@ -1,7 +1,24 @@
|
|||
plugins {
|
||||
// Allow blossom to mark sources root of templates
|
||||
idea
|
||||
id("geyser.publish-conventions")
|
||||
alias(libs.plugins.blossom)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.base.api)
|
||||
}
|
||||
api(libs.math)
|
||||
}
|
||||
|
||||
version = property("version")!!
|
||||
val apiVersion = (version as String).removeSuffix("-SNAPSHOT")
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
javaSources {
|
||||
property("version", apiVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.api;
|
||||
|
||||
import org.geysermc.api.util.ApiVersion;
|
||||
|
||||
/**
|
||||
* Not a public API. For internal use only. May change without notice.
|
||||
* This class is processed before compilation to insert build properties.
|
||||
*/
|
||||
class BuildData {
|
||||
static final String VERSION = "{{ version }}";
|
||||
static final ApiVersion API_VERSION;
|
||||
|
||||
static {
|
||||
String[] parts = VERSION.split("\\.");
|
||||
if (parts.length != 3) {
|
||||
throw new RuntimeException("Invalid api version: " + VERSION);
|
||||
}
|
||||
|
||||
try {
|
||||
int human = Integer.parseInt(parts[0]);
|
||||
int major = Integer.parseInt(parts[1]);
|
||||
int minor = Integer.parseInt(parts[2]);
|
||||
API_VERSION = new ApiVersion(human, major, minor);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Invalid api version: " + VERSION, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,12 +29,15 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.api.Geyser;
|
||||
import org.geysermc.api.GeyserApiBase;
|
||||
import org.geysermc.api.util.ApiVersion;
|
||||
import org.geysermc.geyser.api.command.CommandSource;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.event.EventBus;
|
||||
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||
import org.geysermc.geyser.api.network.BedrockListener;
|
||||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
import org.geysermc.geyser.api.util.MinecraftVersion;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
@ -77,6 +80,7 @@ public interface GeyserApi extends GeyserApiBase {
|
|||
* @param apiClass the builder class
|
||||
* @param <R> the implementation type
|
||||
* @param <T> the API type
|
||||
* @throws IllegalArgumentException if there is no provider for the specified API class
|
||||
* @return the builder instance
|
||||
*/
|
||||
@NonNull
|
||||
|
@ -133,6 +137,30 @@ public interface GeyserApi extends GeyserApiBase {
|
|||
@NonNull
|
||||
PlatformType platformType();
|
||||
|
||||
/**
|
||||
* Gets the version of Java Minecraft that is supported.
|
||||
*
|
||||
* @return the supported version of Java Minecraft
|
||||
*/
|
||||
@NonNull
|
||||
MinecraftVersion supportedJavaVersion();
|
||||
|
||||
/**
|
||||
* Gets a list of Bedrock Minecraft versions that are supported.
|
||||
*
|
||||
* @return the list of supported Bedrock Minecraft versions
|
||||
*/
|
||||
@NonNull
|
||||
List<MinecraftVersion> supportedBedrockVersions();
|
||||
|
||||
/**
|
||||
* Gets the {@link CommandSource} for the console.
|
||||
*
|
||||
* @return the console command source
|
||||
*/
|
||||
@NonNull
|
||||
CommandSource consoleCommandSource();
|
||||
|
||||
/**
|
||||
* Gets the current {@link GeyserApiBase} instance.
|
||||
*
|
||||
|
@ -142,4 +170,14 @@ public interface GeyserApi extends GeyserApiBase {
|
|||
static GeyserApi api() {
|
||||
return Geyser.api(GeyserApi.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ApiVersion} representing the current Geyser api version.
|
||||
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||
*
|
||||
* @return the current geyser api version
|
||||
*/
|
||||
default ApiVersion geyserApiVersion() {
|
||||
return BuildData.API_VERSION;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This interface holds all the methods that relate to a client's camera.
|
||||
* Can be accessed through {@link GeyserConnection#camera()}.
|
||||
*/
|
||||
public interface CameraData {
|
||||
|
||||
/**
|
||||
* Sends a camera fade instruction to the client.
|
||||
* If an existing camera fade is already in progress, the current fade will be prolonged.
|
||||
* Can be built using {@link CameraFade.Builder}.
|
||||
* To stop a fade early, use {@link #clearCameraInstructions()}.
|
||||
*
|
||||
* @param fade the camera fade instruction to send
|
||||
*/
|
||||
void sendCameraFade(@NonNull CameraFade fade);
|
||||
|
||||
/**
|
||||
* Sends a camera position instruction to the client.
|
||||
* If an existing camera movement is already in progress,
|
||||
* the final camera position will be the one of the latest instruction, and
|
||||
* the (optional) camera fade will be added on top of the existing fade.
|
||||
* Can be built using {@link CameraPosition.Builder}.
|
||||
* To stop reset the camera position/stop ongoing instructions, use {@link #clearCameraInstructions()}.
|
||||
*
|
||||
* @param position the camera position instruction to send
|
||||
*/
|
||||
void sendCameraPosition(@NonNull CameraPosition position);
|
||||
|
||||
/**
|
||||
* Stops all sent camera instructions (fades, movements, and perspective locks).
|
||||
* This will not stop any camera shakes/input locks/fog effects, use the respective methods for those.
|
||||
*/
|
||||
void clearCameraInstructions();
|
||||
|
||||
/**
|
||||
* Forces a {@link CameraPerspective} on the client. This will prevent the client
|
||||
* from changing their camera perspective until it is unlocked via {@link #clearCameraInstructions()}.
|
||||
* <p>
|
||||
* Note: You cannot force a client into a free camera perspective with this method.
|
||||
* To do that, send a {@link CameraPosition} via {@link #sendCameraPosition(CameraPosition)} - it requires a set position
|
||||
* instead of being relative to the player.
|
||||
*
|
||||
* @param perspective the {@link CameraPerspective} to force
|
||||
*/
|
||||
void forceCameraPerspective(@NonNull CameraPerspective perspective);
|
||||
|
||||
/**
|
||||
* Gets the client's current {@link CameraPerspective}, if one is currently forced.
|
||||
* This will return {@code null} if the client is not currently forced into a perspective.
|
||||
* If a perspective is forced, the client will not be able to change their camera perspective until it is unlocked.
|
||||
*
|
||||
* @return the forced perspective, or {@code null} if none is forced
|
||||
*/
|
||||
@Nullable CameraPerspective forcedCameraPerspective();
|
||||
|
||||
/**
|
||||
* Shakes the client's camera.
|
||||
* <p>
|
||||
* If the camera is already shaking with the same {@link CameraShake} type, then the additional intensity
|
||||
* will be layered on top of the existing intensity, with their own distinct durations.<br>
|
||||
* If the existing shake type is different and the new intensity/duration are not positive, the existing shake only
|
||||
* switches to the new type. Otherwise, the existing shake is completely overridden.
|
||||
*
|
||||
* @param intensity the intensity of the shake. The client has a maximum total intensity of 4.
|
||||
* @param duration the time in seconds that the shake will occur for
|
||||
* @param type the type of shake
|
||||
*/
|
||||
void shakeCamera(float intensity, float duration, @NonNull CameraShake type);
|
||||
|
||||
/**
|
||||
* Stops all camera shakes of any type.
|
||||
*/
|
||||
void stopCameraShake();
|
||||
|
||||
/**
|
||||
* Adds the given fog IDs to the fog cache, then sends all fog IDs in the cache to the client.
|
||||
* <p>
|
||||
* Fog IDs can be found <a href="https://wiki.bedrock.dev/documentation/fog-ids.html">here</a>
|
||||
*
|
||||
* @param fogNameSpaces the fog IDs to add. If empty, the existing cached IDs will still be sent.
|
||||
*/
|
||||
void sendFog(String... fogNameSpaces);
|
||||
|
||||
/**
|
||||
* Removes the given fog IDs from the fog cache, then sends all fog IDs in the cache to the client.
|
||||
*
|
||||
* @param fogNameSpaces the fog IDs to remove. If empty, all fog IDs will be removed.
|
||||
*/
|
||||
void removeFog(String... fogNameSpaces);
|
||||
|
||||
/**
|
||||
* Returns an immutable copy of all fog affects currently applied to this client.
|
||||
*/
|
||||
@NonNull
|
||||
Set<String> fogEffects();
|
||||
|
||||
/**
|
||||
* (Un)locks the client's camera, so that they cannot look around.
|
||||
* To ensure the camera is only unlocked when all locks are released, you must supply
|
||||
* a UUID when using method, and use the same UUID to unlock the camera.
|
||||
*
|
||||
* @param lock whether to lock the camera
|
||||
* @param owner the owner of the lock, represented with a UUID
|
||||
* @return if the camera is locked after this method call
|
||||
*/
|
||||
boolean lockCamera(boolean lock, @NonNull UUID owner);
|
||||
|
||||
/**
|
||||
* Returns whether the client's camera is locked.
|
||||
*
|
||||
* @return whether the camera is currently locked
|
||||
*/
|
||||
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,77 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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;
|
||||
|
||||
/**
|
||||
* These are all the easing types that can be used when sending a {@link CameraPosition} instruction.
|
||||
* When using these, the client won't teleport to the new camera position, but instead transition to it.
|
||||
* <p>
|
||||
* See <a href="https://easings.net/">https://easings.net/</a> for more information.
|
||||
*/
|
||||
public enum CameraEaseType {
|
||||
LINEAR("linear"),
|
||||
SPRING("spring"),
|
||||
EASE_IN_SINE("in_sine"),
|
||||
EASE_OUT_SINE("out_sine"),
|
||||
EASE_IN_OUT_SINE("in_out_sine"),
|
||||
EASE_IN_QUAD("in_quad"),
|
||||
EASE_OUT_QUAD("out_quad"),
|
||||
EASE_IN_OUT_QUAD("in_out_quad"),
|
||||
EASE_IN_CUBIC("in_cubic"),
|
||||
EASE_OUT_CUBIC("out_cubic"),
|
||||
EASE_IN_OUT_CUBIC("in_out_cubic"),
|
||||
EASE_IN_QUART("in_quart"),
|
||||
EASE_OUT_QUART("out_quart"),
|
||||
EASE_IN_OUT_QUART("in_out_quart"),
|
||||
EASE_IN_QUINT("in_quint"),
|
||||
EASE_OUT_QUINT("out_quint"),
|
||||
EASE_IN_OUT_QUINT("in_out_quint"),
|
||||
EASE_IN_EXPO("in_expo"),
|
||||
EASE_OUT_EXPO("out_expo"),
|
||||
EASE_IN_OUT_EXPO("in_out_expo"),
|
||||
EASE_IN_CIRC("in_circ"),
|
||||
EASE_OUT_CIRC("out_circ"),
|
||||
EASE_IN_OUT_CIRC("in_out_circ"),
|
||||
EASE_IN_BACK("in_back"),
|
||||
EASE_OUT_BACK("out_back"),
|
||||
EASE_IN_OUT_BACK("in_out_back"),
|
||||
EASE_IN_ELASTIC("in_elastic"),
|
||||
EASE_OUT_ELASTIC("out_elastic"),
|
||||
EASE_IN_OUT_ELASTIC("in_out_elastic"),
|
||||
EASE_IN_BOUNCE("in_bounce"),
|
||||
EASE_OUT_BOUNCE("out_bounce"),
|
||||
EASE_IN_OUT_BOUNCE("in_out_bounce");
|
||||
|
||||
private final String id;
|
||||
|
||||
CameraEaseType(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents a coloured fade overlay on the camera.
|
||||
* <p>
|
||||
* Can be sent with {@link CameraData#sendCameraFade(CameraFade)}, or with a {@link CameraPosition} instruction.
|
||||
*/
|
||||
public interface CameraFade {
|
||||
|
||||
/**
|
||||
* Gets the color overlay of the camera.
|
||||
* Bedrock uses an RGB color system.
|
||||
*
|
||||
* @return the color of the fade
|
||||
*/
|
||||
@NonNull Color color();
|
||||
|
||||
/**
|
||||
* Gets the seconds it takes to fade in.
|
||||
* All fade times combined must take at least 0.5 seconds, and at most 30 seconds.
|
||||
*
|
||||
* @return the seconds it takes to fade in
|
||||
*/
|
||||
float fadeInSeconds();
|
||||
|
||||
/**
|
||||
* Gets the seconds the overlay is held.
|
||||
* All fade times combined must take at least 0.5 seconds, and at most 30 seconds.
|
||||
*
|
||||
* @return the seconds the overlay is held
|
||||
*/
|
||||
float fadeHoldSeconds();
|
||||
|
||||
/**
|
||||
* Gets the seconds it takes to fade out.
|
||||
* All fade times combined must take at least 0.5 seconds, and at most 30 seconds.
|
||||
*
|
||||
* @return the seconds it takes to fade out
|
||||
*/
|
||||
float fadeOutSeconds();
|
||||
|
||||
/**
|
||||
* Creates a Builder for CameraFade
|
||||
*
|
||||
* @return a CameraFade Builder
|
||||
*/
|
||||
static CameraFade.Builder builder() {
|
||||
return GeyserApi.api().provider(CameraFade.Builder.class);
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder color(@NonNull Color color);
|
||||
|
||||
Builder fadeInSeconds(@IntRange(from = 0, to = 10) float fadeInSeconds);
|
||||
|
||||
Builder fadeHoldSeconds(@IntRange(from = 0, to = 10) float fadeHoldSeconds);
|
||||
|
||||
Builder fadeOutSeconds(@IntRange(from = 0, to = 10) float fadeOutSeconds);
|
||||
|
||||
CameraFade build();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
* Copyright (c) 2019-2023 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
|
||||
|
@ -23,23 +23,26 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.level.block;
|
||||
package org.geysermc.geyser.api.bedrock.camera;
|
||||
|
||||
/**
|
||||
* This stores all values of double chests that are part of the Java block state.
|
||||
* Represents a camera perspective that a player's camera can take.
|
||||
* All perspectives except for {@link #FREE} are locked to the player's head,
|
||||
* and are therefore relative to the player's position and rotation.
|
||||
*/
|
||||
public record DoubleChestValue(
|
||||
/**
|
||||
* If true, then chest is facing east/west; if false, south/north
|
||||
*/
|
||||
boolean isFacingEast,
|
||||
/**
|
||||
* If true, direction is positive (east/south); if false, direction is negative (west/north)
|
||||
*/
|
||||
boolean isDirectionPositive,
|
||||
/**
|
||||
* If true, chest is the left of a pair; if false, chest is the right of a pair.
|
||||
*/
|
||||
boolean isLeft) {
|
||||
public enum CameraPerspective {
|
||||
FIRST_PERSON("minecraft:first_person"),
|
||||
FREE("minecraft:free"),
|
||||
THIRD_PERSON("minecraft:third_person"),
|
||||
THIRD_PERSON_FRONT("minecraft:third_person_front");
|
||||
|
||||
private final String id;
|
||||
|
||||
CameraPerspective(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
|
||||
/**
|
||||
* This interface represents a camera position instruction. Can be built with the {@link #builder()}.
|
||||
* <p>
|
||||
* Any camera position instruction pins the client camera to a specific position and rotation.
|
||||
* You can set {@link CameraEaseType} to ensure a smooth transition that will last {@link #easeSeconds()} seconds.
|
||||
* A {@link CameraFade} can also be sent, which will transition the player to a coloured transition during the transition.
|
||||
* <p>
|
||||
* Use {@link CameraData#sendCameraPosition(CameraPosition)} to send such an instruction to any connection.
|
||||
*/
|
||||
public interface CameraPosition {
|
||||
|
||||
/**
|
||||
* Gets the camera's position.
|
||||
*
|
||||
* @return camera position vector
|
||||
*/
|
||||
@NonNull Vector3f position();
|
||||
|
||||
/**
|
||||
* Gets the {@link CameraEaseType} of the camera.
|
||||
* If not set, there is no easing.
|
||||
*
|
||||
* @return camera ease type
|
||||
*/
|
||||
@Nullable CameraEaseType easeType();
|
||||
|
||||
/**
|
||||
* Gets the {@link CameraFade} to be sent along the camera position instruction.
|
||||
* If set, they will run at once.
|
||||
*
|
||||
* @return camera fade, or null if not present
|
||||
*/
|
||||
@Nullable CameraFade cameraFade();
|
||||
|
||||
/**
|
||||
* Gets the easing duration of the camera, in seconds.
|
||||
* Is only used if a {@link CameraEaseType} is set.
|
||||
*
|
||||
* @return camera easing duration in seconds
|
||||
*/
|
||||
float easeSeconds();
|
||||
|
||||
/**
|
||||
* Gets the x-axis rotation of the camera.
|
||||
* To prevent the camera from being upside down, Bedrock limits the range to -90 to 90.
|
||||
* Will be overridden if {@link #facingPosition()} is set.
|
||||
*
|
||||
* @return camera x-axis rotation
|
||||
*/
|
||||
@IntRange(from = -90, to = 90) int rotationX();
|
||||
|
||||
/**
|
||||
* Gets the y-axis rotation of the camera.
|
||||
* Will be overridden if {@link #facingPosition()} is set.
|
||||
*
|
||||
* @return camera y-axis rotation
|
||||
*/
|
||||
int rotationY();
|
||||
|
||||
/**
|
||||
* Gets the position that the camera is facing.
|
||||
* Can be used instead of manually setting rotation values.
|
||||
* <p>
|
||||
* If set, the rotation values set via {@link #rotationX()} and {@link #rotationY()} will be ignored.
|
||||
*
|
||||
* @return Camera's facing position
|
||||
*/
|
||||
@Nullable Vector3f facingPosition();
|
||||
|
||||
/**
|
||||
* Controls whether player effects, such as night vision or blindness, should be rendered on the camera.
|
||||
* Defaults to false.
|
||||
*
|
||||
* @return whether player effects should be rendered
|
||||
*/
|
||||
boolean renderPlayerEffects();
|
||||
|
||||
/**
|
||||
* Controls whether the player position should be used for directional audio.
|
||||
* If false, the camera position will be used instead.
|
||||
*
|
||||
* @return whether the players position should be used for directional audio
|
||||
*/
|
||||
boolean playerPositionForAudio();
|
||||
|
||||
/**
|
||||
* Creates a Builder for CameraPosition
|
||||
*
|
||||
* @return a CameraPosition Builder
|
||||
*/
|
||||
static CameraPosition.Builder builder() {
|
||||
return GeyserApi.api().provider(CameraPosition.Builder.class);
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
Builder cameraFade(@Nullable CameraFade cameraFade);
|
||||
|
||||
Builder renderPlayerEffects(boolean renderPlayerEffects);
|
||||
|
||||
Builder playerPositionForAudio(boolean playerPositionForAudio);
|
||||
|
||||
Builder easeType(@Nullable CameraEaseType easeType);
|
||||
|
||||
Builder easeSeconds(float easeSeconds);
|
||||
|
||||
Builder position(@NonNull Vector3f position);
|
||||
|
||||
Builder rotationX(@IntRange(from = -90, to = 90) int rotationX);
|
||||
|
||||
Builder rotationY(int rotationY);
|
||||
|
||||
Builder facingPosition(@Nullable Vector3f facingPosition);
|
||||
|
||||
CameraPosition build();
|
||||
}
|
||||
}
|
|
@ -25,7 +25,10 @@
|
|||
|
||||
package org.geysermc.geyser.api.bedrock.camera;
|
||||
|
||||
/**
|
||||
* Represents a camera shake instruction. Can be sent in {@link CameraData#shakeCamera(float, float, CameraShake)}
|
||||
*/
|
||||
public enum CameraShake {
|
||||
POSITIONAL,
|
||||
ROTATIONAL;
|
||||
ROTATIONAL
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -61,16 +61,16 @@ public interface CustomBlockData {
|
|||
boolean includedInCreativeInventory();
|
||||
|
||||
/**
|
||||
* Gets the item's creative category, or tab id.
|
||||
* Gets the block's creative category, or tab id.
|
||||
*
|
||||
* @return the item's creative category
|
||||
* @return the block's creative category
|
||||
*/
|
||||
@Nullable CreativeCategory creativeCategory();
|
||||
|
||||
/**
|
||||
* Gets the item's creative group.
|
||||
* Gets the block's creative group.
|
||||
*
|
||||
* @return the item's creative group
|
||||
* @return the block's creative group
|
||||
*/
|
||||
@Nullable String creativeGroup();
|
||||
|
||||
|
|
|
@ -129,8 +129,11 @@ public interface CustomBlockComponents {
|
|||
* Gets the unit cube component
|
||||
* Equivalent to "minecraft:unit_cube"
|
||||
*
|
||||
* @deprecated Use {@link #geometry()} and compare with `minecraft:geometry.full_block` instead.
|
||||
*
|
||||
* @return The rotation.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean unitCube();
|
||||
|
||||
/**
|
||||
|
@ -181,11 +184,15 @@ public interface CustomBlockComponents {
|
|||
|
||||
Builder transformation(TransformationComponent transformation);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #geometry(GeometryComponent)} with `minecraft:geometry.full_block` instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Builder unitCube(boolean unitCube);
|
||||
|
||||
Builder placeAir(boolean placeAir);
|
||||
|
||||
Builder tags(Set<String> tags);
|
||||
Builder tags(@Nullable Set<String> tags);
|
||||
|
||||
CustomBlockComponents build();
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
|
||||
package org.geysermc.geyser.api.block.custom.component;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* This class is used to store conditions for a placement filter for a custom block.
|
||||
*
|
||||
|
@ -43,7 +43,7 @@ public record PlacementConditions(@NonNull Set<Face> allowedFaces, @NonNull Link
|
|||
NORTH,
|
||||
SOUTH,
|
||||
WEST,
|
||||
EAST;
|
||||
EAST
|
||||
}
|
||||
|
||||
public enum BlockFilterType {
|
||||
|
|
|
@ -39,7 +39,7 @@ public interface JavaBlockState {
|
|||
*
|
||||
* @return whether the block state is waterlogged
|
||||
*/
|
||||
@NonNull boolean waterlogged();
|
||||
boolean waterlogged();
|
||||
|
||||
/**
|
||||
* Gets the collision of the block state
|
||||
|
@ -53,7 +53,7 @@ public interface JavaBlockState {
|
|||
*
|
||||
* @return whether the block state can be broken with hand
|
||||
*/
|
||||
@NonNull boolean canBreakWithHand();
|
||||
boolean canBreakWithHand();
|
||||
|
||||
/**
|
||||
* Gets the pick item of the block state
|
||||
|
@ -73,8 +73,11 @@ public interface JavaBlockState {
|
|||
* Gets whether the block state has block entity
|
||||
*
|
||||
* @return whether the block state has block entity
|
||||
* @deprecated Does not have an effect. If you were using this to
|
||||
* set piston behavior, use {@link #pistonBehavior()} instead.
|
||||
*/
|
||||
@Nullable boolean hasBlockEntity();
|
||||
@Deprecated(forRemoval = true)
|
||||
boolean hasBlockEntity();
|
||||
|
||||
/**
|
||||
* Creates a new {@link JavaBlockState.Builder} instance
|
||||
|
@ -94,17 +97,22 @@ public interface JavaBlockState {
|
|||
|
||||
Builder blockHardness(@NonNegative float blockHardness);
|
||||
|
||||
Builder waterlogged(@NonNull boolean waterlogged);
|
||||
Builder waterlogged(boolean waterlogged);
|
||||
|
||||
Builder collision(@NonNull JavaBoundingBox[] collision);
|
||||
|
||||
Builder canBreakWithHand(@NonNull boolean canBreakWithHand);
|
||||
Builder canBreakWithHand(boolean canBreakWithHand);
|
||||
|
||||
Builder pickItem(@Nullable String pickItem);
|
||||
|
||||
Builder pistonBehavior(@Nullable String pistonBehavior);
|
||||
|
||||
Builder hasBlockEntity(@Nullable boolean hasBlockEntity);
|
||||
/**
|
||||
* @deprecated Does not have an effect. If you were using this to
|
||||
* * set piston behavior, use {@link #pistonBehavior(String)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
Builder hasBlockEntity(boolean hasBlockEntity);
|
||||
|
||||
JavaBlockState build();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
package org.geysermc.geyser.api.block.custom.nonvanilla;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public record JavaBoundingBox(@NonNull double middleX, @NonNull double middleY, @NonNull double middleZ, @NonNull double sizeX, @NonNull double sizeY, @NonNull double sizeZ) {
|
||||
public record JavaBoundingBox(double middleX, double middleY, double middleZ, double sizeX, double sizeY, double sizeZ) {
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ package org.geysermc.geyser.api.command;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.api.util.TriState;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -58,15 +60,15 @@ public interface Command {
|
|||
* Gets the permission node associated with
|
||||
* this command.
|
||||
*
|
||||
* @return the permission node for this command
|
||||
* @return the permission node for this command if defined, otherwise an empty string
|
||||
*/
|
||||
@NonNull
|
||||
String permission();
|
||||
|
||||
/**
|
||||
* Gets the aliases for this command.
|
||||
* Gets the aliases for this command, as an unmodifiable list
|
||||
*
|
||||
* @return the aliases for this command
|
||||
* @return the aliases for this command as an unmodifiable list
|
||||
*/
|
||||
@NonNull
|
||||
List<String> aliases();
|
||||
|
@ -75,35 +77,39 @@ public interface Command {
|
|||
* Gets if this command is designed to be used only by server operators.
|
||||
*
|
||||
* @return if this command is designated to be used only by server operators.
|
||||
* @deprecated this method is not guaranteed to provide meaningful or expected results.
|
||||
*/
|
||||
boolean isSuggestedOpOnly();
|
||||
|
||||
/**
|
||||
* Gets if this command is executable on console.
|
||||
*
|
||||
* @return if this command is executable on console
|
||||
*/
|
||||
boolean isExecutableOnConsole();
|
||||
|
||||
/**
|
||||
* Gets the subcommands associated with this
|
||||
* command. Mainly used within the Geyser Standalone
|
||||
* GUI to know what subcommands are supported.
|
||||
*
|
||||
* @return the subcommands associated with this command
|
||||
*/
|
||||
@NonNull
|
||||
default List<String> subCommands() {
|
||||
return Collections.emptyList();
|
||||
@Deprecated(forRemoval = true)
|
||||
default boolean isSuggestedOpOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to send a deny message to Java players if this command can only be used by Bedrock players.
|
||||
*
|
||||
* @return true if this command can only be used by Bedrock players.
|
||||
* @return true if this command is executable on console
|
||||
* @deprecated use {@link #isPlayerOnly()} instead (inverted)
|
||||
*/
|
||||
default boolean isBedrockOnly() {
|
||||
return false;
|
||||
@Deprecated(forRemoval = true)
|
||||
default boolean isExecutableOnConsole() {
|
||||
return !isPlayerOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this command can only be used by players
|
||||
*/
|
||||
boolean isPlayerOnly();
|
||||
|
||||
/**
|
||||
* @return true if this command can only be used by Bedrock players
|
||||
*/
|
||||
boolean isBedrockOnly();
|
||||
|
||||
/**
|
||||
* @deprecated this method will always return an empty immutable list
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@NonNull
|
||||
default List<String> subCommands() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,7 +134,7 @@ public interface Command {
|
|||
* is an instance of this source.
|
||||
*
|
||||
* @param sourceType the source type
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> source(@NonNull Class<? extends T> sourceType);
|
||||
|
||||
|
@ -136,7 +142,7 @@ public interface Command {
|
|||
* Sets the command name.
|
||||
*
|
||||
* @param name the command name
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> name(@NonNull String name);
|
||||
|
||||
|
@ -144,23 +150,40 @@ public interface Command {
|
|||
* Sets the command description.
|
||||
*
|
||||
* @param description the command description
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> description(@NonNull String description);
|
||||
|
||||
/**
|
||||
* Sets the permission node.
|
||||
* Sets the permission node required to run this command. <br>
|
||||
* It will not be registered with any permission registries, such as an underlying server,
|
||||
* or a permissions Extension (unlike {@link #permission(String, TriState)}).
|
||||
*
|
||||
* @param permission the permission node
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> permission(@NonNull String permission);
|
||||
|
||||
/**
|
||||
* Sets the permission node and its default value. The usage of the default value is platform dependant
|
||||
* and may or may not be used. For example, it may be registered to an underlying server.
|
||||
* <p>
|
||||
* Extensions may instead listen for {@link GeyserRegisterPermissionsEvent} to register permissions,
|
||||
* especially if the same permission is required by multiple commands. Also see this event for TriState meanings.
|
||||
*
|
||||
* @param permission the permission node
|
||||
* @param defaultValue the node's default value
|
||||
* @return this builder
|
||||
* @deprecated this method is experimental and may be removed in the future
|
||||
*/
|
||||
@Deprecated
|
||||
Builder<T> permission(@NonNull String permission, @NonNull TriState defaultValue);
|
||||
|
||||
/**
|
||||
* Sets the aliases.
|
||||
*
|
||||
* @param aliases the aliases
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> aliases(@NonNull List<String> aliases);
|
||||
|
||||
|
@ -168,46 +191,62 @@ public interface Command {
|
|||
* Sets if this command is designed to be used only by server operators.
|
||||
*
|
||||
* @param suggestedOpOnly if this command is designed to be used only by server operators
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
* @deprecated this method is not guaranteed to produce meaningful or expected results
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
Builder<T> suggestedOpOnly(boolean suggestedOpOnly);
|
||||
|
||||
/**
|
||||
* Sets if this command is executable on console.
|
||||
*
|
||||
* @param executableOnConsole if this command is executable on console
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
* @deprecated use {@link #isPlayerOnly()} instead (inverted)
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
Builder<T> executableOnConsole(boolean executableOnConsole);
|
||||
|
||||
/**
|
||||
* Sets if this command can only be executed by players.
|
||||
*
|
||||
* @param playerOnly if this command is player only
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> playerOnly(boolean playerOnly);
|
||||
|
||||
/**
|
||||
* Sets if this command can only be executed by bedrock players.
|
||||
*
|
||||
* @param bedrockOnly if this command is bedrock only
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> bedrockOnly(boolean bedrockOnly);
|
||||
|
||||
/**
|
||||
* Sets the subcommands.
|
||||
*
|
||||
* @param subCommands the subcommands
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
* @deprecated this method has no effect
|
||||
*/
|
||||
Builder<T> subCommands(@NonNull List<String> subCommands);
|
||||
|
||||
/**
|
||||
* Sets if this command is bedrock only.
|
||||
*
|
||||
* @param bedrockOnly if this command is bedrock only
|
||||
* @return the builder
|
||||
*/
|
||||
Builder<T> bedrockOnly(boolean bedrockOnly);
|
||||
@Deprecated(forRemoval = true)
|
||||
default Builder<T> subCommands(@NonNull List<String> subCommands) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link CommandExecutor} for this command.
|
||||
*
|
||||
* @param executor the command executor
|
||||
* @return the builder
|
||||
* @return this builder
|
||||
*/
|
||||
Builder<T> executor(@NonNull CommandExecutor<T> executor);
|
||||
|
||||
/**
|
||||
* Builds the command.
|
||||
*
|
||||
* @return the command
|
||||
* @return a new command from this builder
|
||||
*/
|
||||
@NonNull
|
||||
Command build();
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
package org.geysermc.geyser.api.command;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents an instance capable of sending commands.
|
||||
|
@ -64,6 +68,17 @@ public interface CommandSource {
|
|||
*/
|
||||
boolean isConsole();
|
||||
|
||||
/**
|
||||
* @return a Java UUID if this source represents a player, otherwise null
|
||||
*/
|
||||
@Nullable UUID playerUuid();
|
||||
|
||||
/**
|
||||
* @return a GeyserConnection if this source represents a Bedrock player that is connected
|
||||
* to this Geyser instance, otherwise null
|
||||
*/
|
||||
@Nullable GeyserConnection connection();
|
||||
|
||||
/**
|
||||
* Returns the locale of the command source.
|
||||
*
|
||||
|
|
|
@ -29,8 +29,10 @@ import org.checkerframework.checker.index.qual.NonNegative;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.api.connection.Connection;
|
||||
import org.geysermc.geyser.api.bedrock.camera.CameraData;
|
||||
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
|
||||
import org.geysermc.geyser.api.command.CommandSource;
|
||||
import org.geysermc.geyser.api.entity.EntityData;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
||||
|
||||
|
@ -41,10 +43,29 @@ import java.util.concurrent.CompletableFuture;
|
|||
* Represents a player connection used in Geyser.
|
||||
*/
|
||||
public interface GeyserConnection extends Connection, CommandSource {
|
||||
|
||||
/**
|
||||
* Exposes the {@link CameraData} for this connection.
|
||||
* It allows you to send fogs, camera shakes, force camera perspectives, and more.
|
||||
*
|
||||
* @return the CameraData for this connection.
|
||||
*/
|
||||
@NonNull CameraData camera();
|
||||
|
||||
/**
|
||||
* Exposes the {@link EntityData} for this connection.
|
||||
* It allows you to get entities by their Java entity ID, show emotes, and get the player entity.
|
||||
*
|
||||
* @return the EntityData for this connection.
|
||||
*/
|
||||
@NonNull EntityData entities();
|
||||
|
||||
/**
|
||||
* @param javaId the Java entity ID to look up.
|
||||
* @return a {@link GeyserEntity} if present in this connection's entity tracker.
|
||||
* @deprecated Use {@link EntityData#entityByJavaId(int)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId);
|
||||
|
||||
|
@ -53,11 +74,14 @@ public interface GeyserConnection extends Connection, CommandSource {
|
|||
*
|
||||
* @param emoter the player entity emoting.
|
||||
* @param emoteId the emote ID to send to this client.
|
||||
* @deprecated use {@link EntityData#showEmote(GeyserPlayerEntity, String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
void showEmote(@NonNull GeyserPlayerEntity emoter, @NonNull String emoteId);
|
||||
|
||||
/**
|
||||
* Shakes the client's camera.<br><br>
|
||||
* Shakes the client's camera.
|
||||
* <p>
|
||||
* If the camera is already shaking with the same {@link CameraShake} type, then the additional intensity
|
||||
* will be layered on top of the existing intensity, with their own distinct durations.<br>
|
||||
* If the existing shake type is different and the new intensity/duration are not positive, the existing shake only
|
||||
|
@ -66,12 +90,18 @@ public interface GeyserConnection extends Connection, CommandSource {
|
|||
* @param intensity the intensity of the shake. The client has a maximum total intensity of 4.
|
||||
* @param duration the time in seconds that the shake will occur for
|
||||
* @param type the type of shake
|
||||
*
|
||||
* @deprecated Use {@link CameraData#shakeCamera(float, float, CameraShake)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void shakeCamera(float intensity, float duration, @NonNull CameraShake type);
|
||||
|
||||
/**
|
||||
* Stops all camera shake of any type.
|
||||
*
|
||||
* @deprecated Use {@link CameraData#stopCameraShake()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void stopCameraShake();
|
||||
|
||||
/**
|
||||
|
@ -80,19 +110,31 @@ public interface GeyserConnection extends Connection, CommandSource {
|
|||
* Fog IDs can be found <a href="https://wiki.bedrock.dev/documentation/fog-ids.html">here</a>
|
||||
*
|
||||
* @param fogNameSpaces the fog IDs to add. If empty, the existing cached IDs will still be sent.
|
||||
* @deprecated Use {@link CameraData#sendFog(String...)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void sendFog(String... fogNameSpaces);
|
||||
|
||||
/**
|
||||
* Removes the given fog IDs from the fog cache, then sends all fog IDs in the cache to the client.
|
||||
*
|
||||
* @param fogNameSpaces the fog IDs to remove. If empty, all fog IDs will be removed.
|
||||
* @deprecated Use {@link CameraData#removeFog(String...)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void removeFog(String... fogNameSpaces);
|
||||
|
||||
/**
|
||||
* Returns an immutable copy of all fog affects currently applied to this client.
|
||||
*
|
||||
* @deprecated Use {@link CameraData#fogEffects()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
Set<String> fogEffects();
|
||||
|
||||
/**
|
||||
* Returns the current ping of the connection.
|
||||
*/
|
||||
int ping();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.entity;
|
||||
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* This class holds all the methods that relate to entities.
|
||||
* Can be accessed through {@link GeyserConnection#entities()}.
|
||||
*/
|
||||
public interface EntityData {
|
||||
|
||||
/**
|
||||
* Returns a {@link GeyserEntity} to e.g. make them play an emote.
|
||||
*
|
||||
* @param javaId the Java entity ID to look up
|
||||
* @return a {@link GeyserEntity} if present in this connection's entity tracker
|
||||
*/
|
||||
@NonNull CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId);
|
||||
|
||||
/**
|
||||
* Displays a player entity as emoting to this client.
|
||||
*
|
||||
* @param emoter the player entity emoting
|
||||
* @param emoteId the emote ID to send to this client
|
||||
*/
|
||||
void showEmote(@NonNull GeyserPlayerEntity emoter, @NonNull String emoteId);
|
||||
|
||||
/**
|
||||
* Gets the {@link GeyserPlayerEntity} of this connection.
|
||||
*
|
||||
* @return the {@link GeyserPlayerEntity} of this connection
|
||||
*/
|
||||
@NonNull GeyserPlayerEntity playerEntity();
|
||||
|
||||
/**
|
||||
* (Un)locks the client's movement inputs, so that they cannot move.
|
||||
* To ensure that movement is only unlocked when all locks are released, you must supply
|
||||
* a UUID with this method, and use the same UUID to unlock the camera.
|
||||
*
|
||||
* @param lock whether to lock the movement
|
||||
* @param owner the owner of the lock
|
||||
* @return if the movement is locked after this method call
|
||||
*/
|
||||
boolean lockMovement(boolean lock, @NonNull UUID owner);
|
||||
|
||||
/**
|
||||
* Returns whether the client's movement is currently locked.
|
||||
*
|
||||
* @return whether the movement is locked
|
||||
*/
|
||||
boolean isMovementLocked();
|
||||
|
||||
/**
|
||||
* Sends a request to the Java server to switch the items in the main and offhand.
|
||||
* There is no guarantee of the server accepting the request.
|
||||
*/
|
||||
void switchHands();
|
||||
}
|
|
@ -25,7 +25,15 @@
|
|||
|
||||
package org.geysermc.geyser.api.entity.type.player;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
|
||||
public interface GeyserPlayerEntity extends GeyserEntity {
|
||||
|
||||
/**
|
||||
* Gets the position of the player.
|
||||
*
|
||||
* @return the position of the player.
|
||||
*/
|
||||
Vector3f position();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.geyser.api.event;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.event.bus.OwnedEventBus;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.api.event;
|
|||
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.event.subscribe.OwnedSubscriber;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
|
||||
/**
|
||||
* Represents a subscribed listener to a {@link Event}. Wraps around
|
||||
|
|
|
@ -23,31 +23,39 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.type;
|
||||
package org.geysermc.geyser.api.event.bedrock;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||
|
||||
public class ChestItem extends BlockItem {
|
||||
/**
|
||||
* Called when a Geyser session disconnects.
|
||||
*/
|
||||
public class SessionDisconnectEvent extends ConnectionEvent {
|
||||
private String disconnectReason;
|
||||
|
||||
public ChestItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
public SessionDisconnectEvent(@NonNull GeyserConnection connection, @NonNull String reason) {
|
||||
super(connection);
|
||||
this.disconnectReason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) {
|
||||
super.translateNbtToBedrock(session, tag);
|
||||
/**
|
||||
* Gets the disconnect reason.
|
||||
*
|
||||
* @return the reason for the disconnect
|
||||
*/
|
||||
public @NonNull String disconnectReason() {
|
||||
return disconnectReason;
|
||||
}
|
||||
|
||||
// Strip the BlockEntityTag from the chests contents
|
||||
// sent to the client. The client does not parse this
|
||||
// or use it for anything, as this tag is fully
|
||||
// server-side, so we remove it to reduce bandwidth and
|
||||
// solve potential issues with very large tags.
|
||||
|
||||
// There was a problem in the past where this would strip
|
||||
// NBT data in creative mode, however with the new server
|
||||
// authoritative inventories, this is no longer a concern.
|
||||
tag.remove("BlockEntityTag");
|
||||
/**
|
||||
* Sets the disconnect reason, thereby overriding th original reason.
|
||||
*
|
||||
* @param disconnectReason the reason for the disconnect
|
||||
*/
|
||||
public void disconnectReason(@NonNull String disconnectReason) {
|
||||
this.disconnectReason = disconnectReason;
|
||||
}
|
||||
}
|
||||
|
|
@ -32,18 +32,27 @@ import org.geysermc.geyser.api.connection.GeyserConnection;
|
|||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
|
||||
import java.util.Map;
|
||||
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.
|
||||
*/
|
||||
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
|
||||
private RemoteServer remoteServer;
|
||||
private boolean cancelled;
|
||||
private String disconnectReason;
|
||||
private Map<String, byte[]> cookies;
|
||||
private boolean transferring;
|
||||
|
||||
public SessionLoginEvent(@NonNull GeyserConnection connection, @NonNull RemoteServer remoteServer) {
|
||||
public SessionLoginEvent(@NonNull GeyserConnection connection,
|
||||
@NonNull RemoteServer remoteServer,
|
||||
@NonNull Map<String, byte[]> cookies) {
|
||||
super(connection);
|
||||
this.remoteServer = remoteServer;
|
||||
this.cookies = cookies;
|
||||
this.transferring = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,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() {
|
||||
return this.remoteServer;
|
||||
|
@ -106,4 +115,36 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella
|
|||
public void remoteServer(@NonNull RemoteServer remoteServer) {
|
||||
this.remoteServer = remoteServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of cookies from a possible previous session. The Java server can send and request these
|
||||
* to store information on the client across server transfers.
|
||||
*/
|
||||
public void cookies(@NonNull Map<String, byte[]> cookies) {
|
||||
Objects.requireNonNull(cookies);
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map of the sessions cookies, if set.
|
||||
* @return the connections cookies
|
||||
*/
|
||||
public @NonNull Map<String, byte[]> cookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the connection intent of the connection
|
||||
*/
|
||||
public void transferring(boolean transferring) {
|
||||
this.transferring = transferring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this login attempt to the Java server
|
||||
* has the transfer intent
|
||||
*/
|
||||
public boolean transferring() {
|
||||
return this.transferring;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.connection;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.event.Cancellable;
|
||||
import org.geysermc.event.Event;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Called whenever a client attempts to connect to the server, before the connection is accepted.
|
||||
*/
|
||||
public final class ConnectionRequestEvent implements Event, Cancellable {
|
||||
|
||||
private boolean cancelled;
|
||||
private final InetSocketAddress ip;
|
||||
private final InetSocketAddress proxyIp;
|
||||
|
||||
public ConnectionRequestEvent(@NonNull InetSocketAddress ip, @Nullable InetSocketAddress proxyIp) {
|
||||
this.ip = ip;
|
||||
this.proxyIp = proxyIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP address of the client attempting to connect
|
||||
*
|
||||
* @return the IP address of the client attempting to connect
|
||||
* @deprecated Use {@link #inetSocketAddress()} instead
|
||||
*/
|
||||
@NonNull @Deprecated(forRemoval = true)
|
||||
public InetSocketAddress getInetSocketAddress() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP address of the proxy handling the connection. It will return null if there is no proxy.
|
||||
*
|
||||
* @return the IP address of the proxy handling the connection
|
||||
* @deprecated Use {@link #proxyIp()} instead
|
||||
*/
|
||||
@Nullable @Deprecated(forRemoval = true)
|
||||
public InetSocketAddress getProxyIp() {
|
||||
return proxyIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP address of the client attempting to connect
|
||||
*
|
||||
* @return the IP address of the client attempting to connect
|
||||
*/
|
||||
@NonNull
|
||||
public InetSocketAddress inetSocketAddress() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP address of the proxy handling the connection. It will return null if there is no proxy.
|
||||
*
|
||||
* @return the IP address of the proxy handling the connection
|
||||
*/
|
||||
@Nullable
|
||||
public InetSocketAddress proxyIp() {
|
||||
return proxyIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cancel status of this event. If this event is cancelled, the connection will be rejected.
|
||||
*
|
||||
* @return the cancel status of this event
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cancel status of this event. If this event is canceled, the connection will be rejected.
|
||||
*
|
||||
* @param cancelled the cancel status of this event.
|
||||
*/
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ import java.net.InetSocketAddress;
|
|||
|
||||
/**
|
||||
* Called whenever Geyser gets pinged
|
||||
*
|
||||
* <p>
|
||||
* This event allows you to modify/obtain the MOTD, maximum player count, and current number of players online,
|
||||
* Geyser will reply to the client with what was given.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.java;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Fired when the Java server sends a transfer request to a different Java server.
|
||||
* Geyser Extensions can listen to this event and set a target server ip/port for Bedrock players to be transferred to.
|
||||
*/
|
||||
public class ServerTransferEvent extends ConnectionEvent {
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
private String bedrockHost;
|
||||
private int bedrockPort;
|
||||
private final Map<String, byte[]> cookies;
|
||||
|
||||
public ServerTransferEvent(@NonNull GeyserConnection connection,
|
||||
@NonNull String host, int port, @NonNull Map<String, byte[]> cookies) {
|
||||
super(connection);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.cookies = cookies;
|
||||
this.bedrockHost = null;
|
||||
this.bedrockPort = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The host that the Java server requests a transfer to.
|
||||
*
|
||||
* @return the host
|
||||
*/
|
||||
public @NonNull String host() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* The port that the Java server requests a transfer to.
|
||||
*
|
||||
* @return the port
|
||||
*/
|
||||
public int port() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* The host that the Bedrock player should try and connect to.
|
||||
* If this is not set, the Bedrock player will just be disconnected.
|
||||
*
|
||||
* @return the host where the Bedrock client will be transferred to, or null if not set.
|
||||
*/
|
||||
public @Nullable String bedrockHost() {
|
||||
return this.bedrockHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* The port that the Bedrock player should try and connect to.
|
||||
* If this is not set, the Bedrock player will just be disconnected.
|
||||
*
|
||||
* @return the port where the Bedrock client will be transferred to, or -1 if not set.
|
||||
*/
|
||||
public int bedrockPort() {
|
||||
return this.bedrockPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host for the Bedrock player to be transferred to
|
||||
*/
|
||||
public void bedrockHost(@NonNull String host) {
|
||||
if (host == null || host.isBlank()) {
|
||||
throw new IllegalArgumentException("Server address cannot be null or blank");
|
||||
}
|
||||
this.bedrockHost = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port for the Bedrock player to be transferred to
|
||||
*/
|
||||
public void bedrockPort(@IntRange(from = 0, to = 65535) int port) {
|
||||
if (port < 0 || port > 65535) {
|
||||
throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port);
|
||||
}
|
||||
this.bedrockPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map of the sessions current cookies.
|
||||
*
|
||||
* @return the connections cookies
|
||||
*/
|
||||
public @NonNull Map<String, byte[]> cookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* Called when commands are defined within Geyser.
|
||||
*
|
||||
* <p>
|
||||
* This event allows you to register new commands using the {@link #register(Command)}
|
||||
* method and retrieve the default commands defined.
|
||||
*/
|
||||
|
@ -50,7 +50,7 @@ public interface GeyserDefineCommandsEvent extends Event {
|
|||
/**
|
||||
* Gets all the registered built-in {@link Command}s.
|
||||
*
|
||||
* @return all the registered built-in commands
|
||||
* @return all the registered built-in commands as an unmodifiable map
|
||||
*/
|
||||
@NonNull
|
||||
Map<String, Command> commands();
|
||||
|
|
|
@ -28,13 +28,12 @@ package org.geysermc.geyser.api.event.lifecycle;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockData;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockItem;
|
||||
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
|
||||
import org.geysermc.event.Event;
|
||||
|
||||
/**
|
||||
* Called on Geyser's startup when looking for custom blocks. Custom blocks must be registered through this event.
|
||||
*
|
||||
* <p>
|
||||
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||
*/
|
||||
public abstract class GeyserDefineCustomBlocksEvent implements Event {
|
||||
|
@ -48,8 +47,8 @@ public abstract class GeyserDefineCustomBlocksEvent implements Event {
|
|||
/**
|
||||
* Registers the given {@link CustomBlockState} as an override for the
|
||||
* given java state identifier
|
||||
* Java state identifiers are listed in
|
||||
* https://raw.githubusercontent.com/GeyserMC/mappings/master/blocks.json
|
||||
* Java state identifiers are listed
|
||||
* <a href="https://raw.githubusercontent.com/GeyserMC/mappings/master/blocks.json">here</a>
|
||||
*
|
||||
* @param javaIdentifier the java state identifier to override
|
||||
* @param customBlockState the custom block state with which to override java state identifier
|
||||
|
|
|
@ -36,7 +36,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* Called on Geyser's startup when looking for custom items. Custom items must be registered through this event.
|
||||
*
|
||||
* <p>
|
||||
* This event will not be called if the "add non-Bedrock items" setting is disabled in the Geyser config.
|
||||
*/
|
||||
public interface GeyserDefineCustomItemsEvent extends Event {
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.geysermc.event.Event;
|
|||
|
||||
/**
|
||||
* Called on Geyser's startup when looking for custom skulls. Custom skulls must be registered through this event.
|
||||
*
|
||||
* <p>
|
||||
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||
*/
|
||||
public abstract class GeyserDefineCustomSkullsEvent implements Event {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.lifecycle;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.geyser.api.event.EventBus;
|
||||
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||
|
||||
/**
|
||||
* Called when Geyser finished reloading and is accepting Bedrock connections again.
|
||||
* Equivalent to the {@link GeyserPostInitializeEvent}
|
||||
*
|
||||
* @param extensionManager the extension manager
|
||||
* @param eventBus the event bus
|
||||
*/
|
||||
public record GeyserPostReloadEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus<EventRegistrar> eventBus) implements Event {
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.lifecycle;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.geyser.api.event.EventBus;
|
||||
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||
|
||||
/**
|
||||
* Called when Geyser is about to reload. Primarily aimed at extensions, so they can decide on their own what to reload.
|
||||
* After this event is fired, some lifecycle events can be fired again - such as the {@link GeyserLoadResourcePacksEvent}.
|
||||
*
|
||||
* @param extensionManager the extension manager
|
||||
* @param eventBus the event bus
|
||||
*/
|
||||
public record GeyserPreReloadEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus<EventRegistrar> eventBus) implements Event {
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.lifecycle;
|
||||
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.event.PostOrder;
|
||||
import org.geysermc.geyser.api.permission.PermissionChecker;
|
||||
|
||||
/**
|
||||
* Fired by any permission manager implementations that wish to add support for custom permission checking.
|
||||
* This event is not guaranteed to be fired - it is currently only fired on Geyser-Standalone and ViaProxy.
|
||||
* <p>
|
||||
* Subscribing to this event with an earlier {@link PostOrder} and registering a {@link PermissionChecker}
|
||||
* will result in that checker having a higher priority than others.
|
||||
*/
|
||||
public interface GeyserRegisterPermissionCheckersEvent extends Event {
|
||||
|
||||
void register(PermissionChecker checker);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.lifecycle;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.geyser.api.util.TriState;
|
||||
|
||||
/**
|
||||
* Fired by anything that wishes to gather permission nodes and defaults.
|
||||
* <p>
|
||||
* This event is not guaranteed to be fired, as certain Geyser platforms do not have a native permission system.
|
||||
* It can be expected to fire on Geyser-Spigot, Geyser-NeoForge, Geyser-Standalone, and Geyser-ViaProxy
|
||||
* It may be fired by a 3rd party regardless of the platform.
|
||||
*/
|
||||
public interface GeyserRegisterPermissionsEvent extends Event {
|
||||
|
||||
/**
|
||||
* Registers a permission node and its default value with the firer.<p>
|
||||
* {@link TriState#TRUE} corresponds to all players having the permission by default.<br>
|
||||
* {@link TriState#NOT_SET} corresponds to only server operators having the permission by default (if such a concept exists on the platform).<br>
|
||||
* {@link TriState#FALSE} corresponds to no players having the permission by default.<br>
|
||||
*
|
||||
* @param permission the permission node to register
|
||||
* @param defaultValue the default value of the node
|
||||
*/
|
||||
void register(@NonNull String permission, @NonNull TriState defaultValue);
|
||||
}
|
|
@ -107,6 +107,15 @@ public interface Extension extends EventRegistrar {
|
|||
return this.extensionLoader().description(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the root command that all of this extension's commands will stem from.
|
||||
* By default, this is the extension's id.
|
||||
*/
|
||||
@NonNull
|
||||
default String rootCommand() {
|
||||
return this.description().id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension's logger
|
||||
*
|
||||
|
|
|
@ -59,33 +59,46 @@ public interface ExtensionDescription {
|
|||
String main();
|
||||
|
||||
/**
|
||||
* Gets the extension's major api version
|
||||
* Represents the human api version that the extension requires.
|
||||
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||
* for more details on the Geyser API version.
|
||||
*
|
||||
* @return the extension's major api version
|
||||
* @return the extension's requested human api version
|
||||
*/
|
||||
int humanApiVersion();
|
||||
|
||||
/**
|
||||
* Represents the major api version that the extension requires.
|
||||
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||
* for more details on the Geyser API version.
|
||||
*
|
||||
* @return the extension's requested major api version
|
||||
*/
|
||||
int majorApiVersion();
|
||||
|
||||
/**
|
||||
* Gets the extension's minor api version
|
||||
* Represents the minor api version that the extension requires.
|
||||
* See the <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">Geyser version outline</a>)
|
||||
* for more details on the Geyser API version.
|
||||
*
|
||||
* @return the extension's minor api version
|
||||
* @return the extension's requested minor api version
|
||||
*/
|
||||
int minorApiVersion();
|
||||
|
||||
/**
|
||||
* Gets the extension's patch api version
|
||||
*
|
||||
* @return the extension's patch api version
|
||||
* No longer in use. Geyser is now using an adaption of the romantic versioning scheme.
|
||||
* See <a href="https://github.com/geysermc/api/blob/master/geyser-versioning.md">here</a> for details.
|
||||
*/
|
||||
int patchApiVersion();
|
||||
@Deprecated(forRemoval = true)
|
||||
default int patchApiVersion() {
|
||||
return minorApiVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension's api version.
|
||||
*
|
||||
* @return the extension's api version
|
||||
* Returns the extension's requested Geyser Api version.
|
||||
*/
|
||||
default String apiVersion() {
|
||||
return majorApiVersion() + "." + minorApiVersion() + "." + patchApiVersion();
|
||||
return humanApiVersion() + "." + majorApiVersion() + "." + minorApiVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,13 +36,13 @@ import java.util.Collection;
|
|||
public abstract class ExtensionManager {
|
||||
|
||||
/**
|
||||
* Gets an extension with the given name.
|
||||
* Gets an extension by the given ID.
|
||||
*
|
||||
* @param name the name of the extension
|
||||
* @return an extension with the given name
|
||||
* @param id the ID of the extension
|
||||
* @return an extension with the given ID
|
||||
*/
|
||||
@Nullable
|
||||
public abstract Extension extension(@NonNull String name);
|
||||
public abstract Extension extension(@NonNull String id);
|
||||
|
||||
/**
|
||||
* Enables the given {@link Extension}.
|
||||
|
|
|
@ -25,10 +25,16 @@
|
|||
|
||||
package org.geysermc.geyser.api.extension.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* Thrown when an extension's description is invalid.
|
||||
*/
|
||||
public class InvalidDescriptionException extends Exception {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidDescriptionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
|
|
@ -25,10 +25,16 @@
|
|||
|
||||
package org.geysermc.geyser.api.extension.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* Thrown when an extension is invalid.
|
||||
*/
|
||||
public class InvalidExtensionException extends Exception {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidExtensionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This is used to store data for a custom item.
|
||||
*/
|
||||
|
@ -75,6 +78,20 @@ public interface CustomItemData {
|
|||
*/
|
||||
boolean displayHandheld();
|
||||
|
||||
/**
|
||||
* Gets the item's creative category, or tab id.
|
||||
*
|
||||
* @return the item's creative category
|
||||
*/
|
||||
@NonNull OptionalInt creativeCategory();
|
||||
|
||||
/**
|
||||
* Gets the item's creative group.
|
||||
*
|
||||
* @return the item's creative group
|
||||
*/
|
||||
@Nullable String creativeGroup();
|
||||
|
||||
/**
|
||||
* Gets the item's texture size. This is to resize the item if the texture is not 16x16.
|
||||
*
|
||||
|
@ -89,6 +106,14 @@ public interface CustomItemData {
|
|||
*/
|
||||
@Nullable CustomRenderOffsets renderOffsets();
|
||||
|
||||
/**
|
||||
* Gets the item's set of tags that can be used in Molang.
|
||||
* Equivalent to "tag:some_tag"
|
||||
*
|
||||
* @return the item's tags, if they exist
|
||||
*/
|
||||
@NonNull Set<String> tags();
|
||||
|
||||
static CustomItemData.Builder builder() {
|
||||
return GeyserApi.api().provider(CustomItemData.Builder.class);
|
||||
}
|
||||
|
@ -109,10 +134,16 @@ public interface CustomItemData {
|
|||
|
||||
Builder displayHandheld(boolean displayHandheld);
|
||||
|
||||
Builder creativeCategory(int creativeCategory);
|
||||
|
||||
Builder creativeGroup(@Nullable String creativeGroup);
|
||||
|
||||
Builder textureSize(int textureSize);
|
||||
|
||||
Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets);
|
||||
|
||||
Builder tags(@Nullable Set<String> tags);
|
||||
|
||||
CustomItemData build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -65,6 +64,14 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
*/
|
||||
int maxDamage();
|
||||
|
||||
/**
|
||||
* Gets the attack damage of the item.
|
||||
* This is purely visual, and only applied to tools
|
||||
*
|
||||
* @return the attack damage of the item
|
||||
*/
|
||||
int attackDamage();
|
||||
|
||||
/**
|
||||
* Gets the tool type of the item.
|
||||
*
|
||||
|
@ -107,20 +114,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
*/
|
||||
@Nullable Set<String> repairMaterials();
|
||||
|
||||
/**
|
||||
* Gets the item's creative category, or tab id.
|
||||
*
|
||||
* @return the item's creative category
|
||||
*/
|
||||
@NonNull OptionalInt creativeCategory();
|
||||
|
||||
/**
|
||||
* Gets the item's creative group.
|
||||
*
|
||||
* @return the item's creative group
|
||||
*/
|
||||
@Nullable String creativeGroup();
|
||||
|
||||
/**
|
||||
* Gets if the item is a hat. This is used to determine if the item should be rendered on the player's head, and
|
||||
* normally allow the player to equip it. This is not meant for armor.
|
||||
|
@ -168,6 +161,13 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
return displayHandheld();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block the item places.
|
||||
*
|
||||
* @return the block the item places
|
||||
*/
|
||||
String block();
|
||||
|
||||
static NonVanillaCustomItemData.Builder builder() {
|
||||
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
|
||||
}
|
||||
|
@ -184,6 +184,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
|
||||
Builder maxDamage(int maxDamage);
|
||||
|
||||
Builder attackDamage(int attackDamage);
|
||||
|
||||
Builder toolType(@Nullable String toolType);
|
||||
|
||||
Builder toolTier(@Nullable String toolTier);
|
||||
|
@ -196,10 +198,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
|
||||
Builder repairMaterials(@Nullable Set<String> repairMaterials);
|
||||
|
||||
Builder creativeCategory(int creativeCategory);
|
||||
|
||||
Builder creativeGroup(@Nullable String creativeGroup);
|
||||
|
||||
Builder hat(boolean isHat);
|
||||
|
||||
Builder foil(boolean isFoil);
|
||||
|
@ -210,6 +208,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
|
||||
Builder chargeable(boolean isChargeable);
|
||||
|
||||
Builder block(String block);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #displayHandheld(boolean)} instead.
|
||||
*/
|
||||
|
@ -218,6 +218,12 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
return displayHandheld(isTool);
|
||||
}
|
||||
|
||||
@Override
|
||||
Builder creativeCategory(int creativeCategory);
|
||||
|
||||
@Override
|
||||
Builder creativeGroup(@Nullable String creativeGroup);
|
||||
|
||||
@Override
|
||||
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);
|
||||
|
||||
|
@ -239,6 +245,9 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
|||
@Override
|
||||
Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets);
|
||||
|
||||
@Override
|
||||
Builder tags(@Nullable Set<String> tags);
|
||||
|
||||
NonVanillaCustomItemData build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,14 @@ public interface BedrockListener {
|
|||
*/
|
||||
int port();
|
||||
|
||||
/**
|
||||
* Gets the broadcast port that's sent to Bedrock clients with the motd.
|
||||
* This is the port that Bedrock clients will connect with. It usually does not differ from the listening port.
|
||||
*
|
||||
* @return the broadcast port
|
||||
*/
|
||||
int broadcastPort();
|
||||
|
||||
/**
|
||||
* Gets the primary MOTD shown to Bedrock players if a ping passthrough setting is not enabled.
|
||||
* <p>
|
||||
|
|
|
@ -42,4 +42,4 @@ public abstract class PathPackCodec extends PackCodec {
|
|||
*/
|
||||
@NonNull
|
||||
public abstract Path path();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.permission;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.command.CommandSource;
|
||||
import org.geysermc.geyser.api.util.TriState;
|
||||
|
||||
/**
|
||||
* Something capable of checking if a {@link CommandSource} has a permission
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PermissionChecker {
|
||||
|
||||
/**
|
||||
* Checks if the given source has a permission
|
||||
*
|
||||
* @param source the {@link CommandSource} whose permissions should be queried
|
||||
* @param permission the permission node to check
|
||||
* @return a {@link TriState} as the value of the node. {@link TriState#NOT_SET} generally means that the permission
|
||||
* node itself was not found, and the source does not have such permission.
|
||||
* {@link TriState#TRUE} and {@link TriState#FALSE} represent explicitly set values.
|
||||
*/
|
||||
@NonNull
|
||||
TriState hasPermission(@NonNull CommandSource source, @NonNull String permission);
|
||||
}
|
|
@ -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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -23,12 +23,18 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.api.skin;
|
||||
|
||||
/**
|
||||
* Contains useful collections for use in Geyser.
|
||||
* Represents a cape.
|
||||
*
|
||||
* Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be
|
||||
* added that are not greater by one versus the previous key. Because of this, speedy operations of {@link java.util.Map#get(java.lang.Object)}
|
||||
* and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map
|
||||
* size and its "start" integer.
|
||||
* @param textureUrl The URL of the cape texture
|
||||
* @param capeId The ID of the cape
|
||||
* @param capeData The raw cape image data in ARGB format
|
||||
* @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);
|
||||
}
|
||||
}
|
39
api/src/main/java/org/geysermc/geyser/api/skin/Skin.java
Normal file
39
api/src/main/java/org/geysermc/geyser/api/skin/Skin.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 skin.
|
||||
*
|
||||
* @param textureUrl The URL/ID of the skin texture
|
||||
* @param skinData The raw skin image data in ARGB
|
||||
* @param failed If the skin failed to load, this is for things like fallback skins
|
||||
*/
|
||||
public record Skin(String textureUrl, byte[] skinData, boolean failed) {
|
||||
public Skin(String textureUrl, byte[] skinData) {
|
||||
this(textureUrl, skinData, false);
|
||||
}
|
||||
}
|
32
api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
Normal file
32
api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
Normal file
|
@ -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) {
|
||||
}
|
|
@ -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" : "") + "\"}}", "");
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -31,11 +31,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
* Represents the creative menu categories or tabs.
|
||||
*/
|
||||
public enum CreativeCategory {
|
||||
COMMANDS("commands", 1),
|
||||
CONSTRUCTION("construction", 2),
|
||||
CONSTRUCTION("construction", 1),
|
||||
NATURE("nature", 2),
|
||||
EQUIPMENT("equipment", 3),
|
||||
ITEMS("items", 4),
|
||||
NATURE("nature", 5),
|
||||
NONE("none", 6);
|
||||
|
||||
private final String internalName;
|
||||
|
@ -51,7 +50,7 @@ public enum CreativeCategory {
|
|||
*
|
||||
* @return the name of the category
|
||||
*/
|
||||
@NonNull public String internalName() {
|
||||
public @NonNull String internalName() {
|
||||
return internalName;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.util;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft version.
|
||||
*/
|
||||
public interface MinecraftVersion {
|
||||
|
||||
/**
|
||||
* Gets the Minecraft version as a String.
|
||||
* Example: "1.20.2", or "1.20.40/1.20.41"
|
||||
*
|
||||
* @return the version string
|
||||
*/
|
||||
@NonNull String versionString();
|
||||
|
||||
/**
|
||||
* Gets the protocol version of this Minecraft version.
|
||||
*
|
||||
* @return the protocol version
|
||||
*/
|
||||
int protocolVersion();
|
||||
}
|
|
@ -34,10 +34,12 @@ public record PlatformType(String platformName) {
|
|||
public static final PlatformType ANDROID = new PlatformType("Android");
|
||||
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
|
||||
public static final PlatformType FABRIC = new PlatformType("Fabric");
|
||||
public static final PlatformType NEOFORGE = new PlatformType("NeoForge");
|
||||
public static final PlatformType SPIGOT = new PlatformType("Spigot");
|
||||
|
||||
@Deprecated
|
||||
public static final PlatformType SPONGE = new PlatformType("Sponge");
|
||||
public static final PlatformType STANDALONE = new PlatformType("Standalone");
|
||||
public static final PlatformType VELOCITY = new PlatformType("Velocity");
|
||||
public static final PlatformType VIAPROXY = new PlatformType("ViaProxy");
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
|
||||
/**
|
||||
* This is a way to represent a boolean, but with a non set value added.
|
||||
* This class was inspired by adventure's version https://github.com/KyoriPowered/adventure/blob/main/4/api/src/main/java/net/kyori/adventure/util/TriState.java
|
||||
* This class was inspired by adventure's <a href="https://github.com/KyoriPowered/adventure/blob/main/4/api/src/main/java/net/kyori/adventure/util/TriState.java">TriState</a>
|
||||
*/
|
||||
public enum TriState {
|
||||
/**
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
dependencies {
|
||||
api(projects.core)
|
||||
|
||||
implementation(libs.cloud.bungee)
|
||||
implementation(libs.adventure.text.serializer.bungeecord)
|
||||
compileOnlyApi(libs.bungeecord.proxy)
|
||||
}
|
||||
|
||||
platformRelocate("net.md_5.bungee.jni")
|
||||
platformRelocate("com.fasterxml.jackson")
|
||||
platformRelocate("io.netty.channel.kqueue") // This is not used because relocating breaks natives, but we must include it or else we get ClassDefNotFound
|
||||
platformRelocate("net.kyori")
|
||||
platformRelocate("org.incendo")
|
||||
platformRelocate("io.leangen.geantyref") // provided by cloud, should also be relocated
|
||||
platformRelocate("org.yaml") // Broken as of 1.20
|
||||
|
||||
// These dependencies are already present on the platform
|
||||
provided(libs.bungeecord.proxy)
|
||||
|
||||
application {
|
||||
mainClass.set("org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain")
|
||||
tasks.withType<Jar> {
|
||||
manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain"
|
||||
}
|
||||
|
||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||
|
@ -22,6 +26,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
|
||||
dependencies {
|
||||
exclude(dependency("com.google.*:.*"))
|
||||
exclude(dependency("io.netty.incubator:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
|
||||
exclude(dependency("io.netty:netty-handler:.*"))
|
||||
|
@ -33,3 +38,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.add("bungeecord")
|
||||
}
|
||||
|
|
|
@ -32,18 +32,26 @@ import net.md_5.bungee.protocol.packet.LoginSuccess;
|
|||
import net.md_5.bungee.protocol.packet.SetCompression;
|
||||
|
||||
public class GeyserBungeeCompressionDisabler extends ChannelOutboundHandlerAdapter {
|
||||
private boolean compressionDisabled = false;
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
if (!(msg instanceof SetCompression)) {
|
||||
if (msg instanceof LoginSuccess) {
|
||||
// We're past the point that compression can be enabled
|
||||
// Fixes https://github.com/GeyserMC/Geyser/issues/4281
|
||||
// The server may send a LoginDisconnect packet after compression is set.
|
||||
if (!compressionDisabled) {
|
||||
if (ctx.pipeline().get("compress") != null) {
|
||||
ctx.pipeline().remove("compress");
|
||||
compressionDisabled = true;
|
||||
}
|
||||
if (ctx.pipeline().get("decompress") != null) {
|
||||
ctx.pipeline().remove("decompress");
|
||||
compressionDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg instanceof LoginSuccess) {
|
||||
// We're past the point that compression can be enabled
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
super.write(ctx, msg, promise);
|
||||
|
|
|
@ -30,6 +30,7 @@ import net.md_5.bungee.api.ProxyServer;
|
|||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -51,7 +52,8 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo {
|
|||
this.plugins = new ArrayList<>();
|
||||
|
||||
for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) {
|
||||
this.listeners.add(new ListenerInfo(listener.getHost().getHostString(), listener.getHost().getPort()));
|
||||
InetSocketAddress address = (InetSocketAddress) listener.getSocketAddress();
|
||||
this.listeners.add(new ListenerInfo(address.getHostString(), address.getPort()));
|
||||
}
|
||||
|
||||
for (Plugin plugin : proxy.getPluginManager().getPlugins()) {
|
||||
|
|
|
@ -39,6 +39,7 @@ import net.md_5.bungee.api.plugin.Listener;
|
|||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.network.netty.GeyserInjector;
|
||||
|
@ -125,7 +126,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener {
|
|||
.channel(LocalServerChannelWrapper.class)
|
||||
.childHandler(new ChannelInitializer<>() {
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
protected void initChannel(@NonNull Channel ch) throws Exception {
|
||||
if (proxy.getConfig().getServers() == null) {
|
||||
// Proxy hasn't finished loading all plugins - it loads the config after all plugins
|
||||
// Probably doesn't need to be translatable?
|
||||
|
|
|
@ -26,22 +26,19 @@
|
|||
package org.geysermc.geyser.platform.bungeecord;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class GeyserBungeeLogger implements GeyserLogger {
|
||||
private final Logger logger;
|
||||
@Getter @Setter
|
||||
private boolean debug;
|
||||
|
||||
public GeyserBungeeLogger(Logger logger, boolean debug) {
|
||||
this.logger = logger;
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message) {
|
||||
logger.severe(message);
|
||||
|
|
|
@ -35,14 +35,16 @@ import net.md_5.bungee.api.connection.PendingConnection;
|
|||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.ping.GeyserPingInfo;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
|
||||
|
@ -59,18 +61,23 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
|||
future.complete(event);
|
||||
}
|
||||
}));
|
||||
ProxyPingEvent event = future.join();
|
||||
ServerPing response = event.getResponse();
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
response.getDescriptionComponent().toLegacyText(),
|
||||
new GeyserPingInfo.Players(response.getPlayers().getMax(), response.getPlayers().getOnline()),
|
||||
new GeyserPingInfo.Version(response.getVersion().getName(), response.getVersion().getProtocol())
|
||||
);
|
||||
if (event.getResponse().getPlayers().getSample() != null) {
|
||||
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer ->
|
||||
geyserPingInfo.getPlayerList().add(proxiedPlayer.getName()));
|
||||
|
||||
ProxyPingEvent event;
|
||||
|
||||
try {
|
||||
event = future.get(100, TimeUnit.MILLISECONDS);
|
||||
} catch (Throwable cause) {
|
||||
String address = GeyserImpl.getInstance().getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : "<IP address withheld>";
|
||||
GeyserImpl.getInstance().getLogger().error("Failed to get ping information for " + address, cause);
|
||||
return null;
|
||||
}
|
||||
return geyserPingInfo;
|
||||
|
||||
ServerPing response = event.getResponse();
|
||||
return new GeyserPingInfo(
|
||||
response.getDescriptionComponent().toLegacyText(),
|
||||
response.getPlayers().getMax(),
|
||||
response.getPlayers().getOnline()
|
||||
);
|
||||
}
|
||||
|
||||
// This is static so pending connection can use it
|
||||
|
@ -110,7 +117,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
|||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getVirtualHost() {
|
||||
public @Nullable InetSocketAddress getVirtualHost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,24 +27,28 @@ package org.geysermc.geyser.platform.bungeecord;
|
|||
|
||||
import io.netty.channel.Channel;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
||||
import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.bungee.BungeeCommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -54,69 +58,117 @@ import java.net.SocketAddress;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private CommandRegistry commandRegistry;
|
||||
private GeyserBungeeConfiguration geyserConfig;
|
||||
private GeyserBungeeInjector geyserInjector;
|
||||
private GeyserBungeeLogger geyserLogger;
|
||||
private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
|
||||
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||
|
||||
private GeyserImpl geyser;
|
||||
|
||||
// We can't disable the plugin; hence we need to keep track of it manually
|
||||
private boolean disabled;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
onGeyserInitialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserInitialize() {
|
||||
GeyserLocale.init(this);
|
||||
|
||||
// Copied from ViaVersion.
|
||||
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
|
||||
try {
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_19_3");
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_21");
|
||||
} catch (NoSuchFieldException e) {
|
||||
getLogger().warning(" / \\");
|
||||
getLogger().warning(" / \\");
|
||||
getLogger().warning(" / | \\");
|
||||
getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
|
||||
getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||
getLogger().warning(" / o \\");
|
||||
getLogger().warning("/_____________\\");
|
||||
geyserLogger.error(" / \\");
|
||||
geyserLogger.error(" / \\");
|
||||
geyserLogger.error(" / | \\");
|
||||
geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
|
||||
geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||
geyserLogger.error(" / o \\");
|
||||
geyserLogger.error("/_____________\\");
|
||||
}
|
||||
|
||||
if (!getDataFolder().exists())
|
||||
getDataFolder().mkdir();
|
||||
|
||||
try {
|
||||
if (!getDataFolder().exists())
|
||||
getDataFolder().mkdir();
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"),
|
||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
if (!this.loadConfig()) {
|
||||
disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
|
||||
this.geyserInjector = new GeyserBungeeInjector(this);
|
||||
|
||||
// Registration of listeners occurs only once
|
||||
this.getProxy().getPluginManager().registerListener(this, new GeyserBungeeUpdateListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
// Remove this in like a year
|
||||
if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) {
|
||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
||||
if (disabled) {
|
||||
return; // Config did not load properly!
|
||||
}
|
||||
// Big hack - Bungee does not provide us an event to listen to, so schedule a repeating
|
||||
// task that waits for a field to be filled which is set after the plugin enable
|
||||
// process is complete
|
||||
this.awaitStartupCompletion(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void awaitStartupCompletion(int tries) {
|
||||
// After 20 tries give up waiting. This will happen just after 3 minutes approximately
|
||||
if (tries >= 20) {
|
||||
this.geyserLogger.warning("BungeeCord plugin startup is taking abnormally long, so Geyser is starting now. " +
|
||||
"If all your plugins are loaded properly, this is a bug! " +
|
||||
"If not, consider cutting down the amount of plugins on your proxy as it is causing abnormally slow starting times.");
|
||||
this.onGeyserEnable();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Field listenersField = BungeeCord.getInstance().getClass().getDeclaredField("listeners");
|
||||
listenersField.setAccessible(true);
|
||||
|
||||
Collection<Channel> listeners = (Collection<Channel>) listenersField.get(BungeeCord.getInstance());
|
||||
if (listeners.isEmpty()) {
|
||||
this.getProxy().getScheduler().schedule(this, this::onGeyserEnable, tries, TimeUnit.SECONDS);
|
||||
} else {
|
||||
this.awaitStartupCompletion(++tries);
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onGeyserEnable() {
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
} else {
|
||||
var sourceConverter = new CommandSourceConverter<>(
|
||||
CommandSender.class,
|
||||
id -> getProxy().getPlayer(id),
|
||||
() -> getProxy().getConsole(),
|
||||
BungeeCommandSource::new
|
||||
);
|
||||
CommandManager<GeyserCommandSource> cloud = new BungeeCommandManager<>(
|
||||
this,
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
sourceConverter
|
||||
);
|
||||
this.commandRegistry = new CommandRegistry(geyser, cloud, false); // applying root permission would be a breaking change because we can't register permission defaults
|
||||
}
|
||||
|
||||
// Force-disable query if enabled, or else Geyser won't enable
|
||||
for (ListenerInfo info : getProxy().getConfig().getListeners()) {
|
||||
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) {
|
||||
|
@ -135,67 +187,31 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
}
|
||||
}
|
||||
|
||||
// Big hack - Bungee does not provide us an event to listen to, so schedule a repeating
|
||||
// task that waits for a field to be filled which is set after the plugin enable
|
||||
// process is complete
|
||||
this.awaitStartupCompletion(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void awaitStartupCompletion(int tries) {
|
||||
// After 20 tries give up waiting. This will happen
|
||||
// just after 3 minutes approximately
|
||||
if (tries >= 20) {
|
||||
this.geyserLogger.warning("BungeeCord plugin startup is taking abnormally long, so Geyser is starting now. " +
|
||||
"If all your plugins are loaded properly, this is a bug! " +
|
||||
"If not, consider cutting down the amount of plugins on your proxy as it is causing abnormally slow starting times.");
|
||||
this.postStartup();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Field listenersField = BungeeCord.getInstance().getClass().getDeclaredField("listeners");
|
||||
listenersField.setAccessible(true);
|
||||
|
||||
Collection<Channel> listeners = (Collection<Channel>) listenersField.get(BungeeCord.getInstance());
|
||||
if (listeners.isEmpty()) {
|
||||
this.getProxy().getScheduler().schedule(this, this::postStartup, tries, TimeUnit.SECONDS);
|
||||
} else {
|
||||
this.awaitStartupCompletion(++tries);
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void postStartup() {
|
||||
GeyserImpl.start();
|
||||
|
||||
this.geyserInjector = new GeyserBungeeInjector(this);
|
||||
this.geyserInjector.initializeLocalChannel(this);
|
||||
|
||||
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||
this.geyserCommandManager.init();
|
||||
|
||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands()));
|
||||
for (Map.Entry<Extension, Map<String, Command>> entry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
||||
Map<String, Command> commands = entry.getValue();
|
||||
if (commands.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(entry.getKey().description().id(), this.geyser, commands));
|
||||
}
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
||||
}
|
||||
|
||||
// No need to re-register commands or re-init injector when reloading
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyserInjector.initializeLocalChannel(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
public void onGeyserDisable() {
|
||||
if (geyser != null) {
|
||||
geyser.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserShutdown() {
|
||||
if (geyser != null) {
|
||||
geyser.shutdown();
|
||||
}
|
||||
|
@ -204,6 +220,11 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.onGeyserShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserBungeeConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
|
@ -215,8 +236,8 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GeyserCommandManager getGeyserCommandManager() {
|
||||
return this.geyserCommandManager;
|
||||
public CommandRegistry getCommandRegistry() {
|
||||
return this.commandRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -245,7 +266,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
return this.geyserInjector.getServerSocketAddress();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@NonNull
|
||||
@Override
|
||||
public String getServerBindAddress() {
|
||||
return findCompatibleListener().map(InetSocketAddress::getHostString).orElse("");
|
||||
|
@ -271,4 +292,20 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
.map(info -> (InetSocketAddress) info.getSocketAddress())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
if (!getDataFolder().exists()) //noinspection ResultOfMethodCallIgnored
|
||||
getDataFolder().mkdir();
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"),
|
||||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.Permissions;
|
||||
import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource;
|
||||
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
|
||||
|
@ -40,7 +40,7 @@ public final class GeyserBungeeUpdateListener implements Listener {
|
|||
public void onPlayerJoin(final PostLoginEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
final ProxiedPlayer player = event.getPlayer();
|
||||
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||
if (player.hasPermission(Permissions.CHECK_UPDATE)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,18 +27,22 @@ package org.geysermc.geyser.platform.bungeecord.command;
|
|||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeCommandSource implements GeyserCommandSource {
|
||||
|
||||
private final net.md_5.bungee.api.CommandSender handle;
|
||||
private final CommandSender handle;
|
||||
|
||||
public BungeeCommandSource(net.md_5.bungee.api.CommandSender handle) {
|
||||
public BungeeCommandSource(CommandSender handle) {
|
||||
this.handle = handle;
|
||||
// Ensure even Java players' languages are loaded
|
||||
GeyserLocale.loadGeyserLocale(this.locale());
|
||||
|
@ -50,7 +54,7 @@ public class BungeeCommandSource implements GeyserCommandSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
public void sendMessage(@NonNull String message) {
|
||||
handle.sendMessage(TextComponent.fromLegacyText(message));
|
||||
}
|
||||
|
||||
|
@ -71,12 +75,20 @@ public class BungeeCommandSource implements GeyserCommandSource {
|
|||
return !(handle instanceof ProxiedPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID playerUuid() {
|
||||
if (handle instanceof ProxiedPlayer player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String locale() {
|
||||
if (handle instanceof ProxiedPlayer player) {
|
||||
Locale locale = player.getLocale();
|
||||
if (locale != null) {
|
||||
// Locale can be null early on in the conneciton
|
||||
// Locale can be null early on in the connection
|
||||
return GeyserLocale.formatLocale(locale.getLanguage() + "_" + locale.getCountry());
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +97,12 @@ public class BungeeCommandSource implements GeyserCommandSource {
|
|||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return handle.hasPermission(permission);
|
||||
// Handle blank permissions ourselves, as bungeecord only handles empty ones
|
||||
return permission.isBlank() || handle.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handle() {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,89 +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.platform.bungeecord.command;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
|
||||
private final GeyserCommandExecutor commandExecutor;
|
||||
|
||||
public GeyserBungeeCommandExecutor(String name, GeyserImpl geyser, Map<String, org.geysermc.geyser.api.command.Command> commands) {
|
||||
super(name);
|
||||
|
||||
this.commandExecutor = new GeyserCommandExecutor(geyser, commands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
BungeeCommandSource commandSender = new BungeeCommandSource(sender);
|
||||
GeyserSession session = this.commandExecutor.getGeyserSession(commandSender);
|
||||
|
||||
if (args.length > 0) {
|
||||
GeyserCommand command = this.commandExecutor.getCommand(args[0]);
|
||||
if (command != null) {
|
||||
if (!sender.hasPermission(command.permission())) {
|
||||
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.locale());
|
||||
|
||||
commandSender.sendMessage(ChatColor.RED + message);
|
||||
return;
|
||||
}
|
||||
if (command.isBedrockOnly() && session == null) {
|
||||
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", commandSender.locale());
|
||||
|
||||
commandSender.sendMessage(ChatColor.RED + message);
|
||||
return;
|
||||
}
|
||||
command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
||||
} else {
|
||||
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale());
|
||||
commandSender.sendMessage(ChatColor.RED + message);
|
||||
}
|
||||
} else {
|
||||
this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return commandExecutor.tabComplete(new BungeeCommandSource(sender));
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
import net.fabricmc.loom.task.RemapJarTask
|
||||
|
||||
plugins {
|
||||
id("fabric-loom") version "1.0-SNAPSHOT"
|
||||
id("com.modrinth.minotaur") version "2.+"
|
||||
}
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//to change the versions see the gradle.properties file
|
||||
minecraft(libs.fabric.minecraft)
|
||||
mappings(loom.officialMojangMappings())
|
||||
modImplementation(libs.fabric.loader)
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation(libs.fabric.api)
|
||||
|
||||
// This should be in the libs TOML, but something about modImplementation AND include just doesn't work
|
||||
include(modImplementation("me.lucko", "fabric-permissions-api", "0.2-SNAPSHOT"))
|
||||
|
||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||
// You may need to force-disable transitiveness on them.
|
||||
|
||||
api(projects.core)
|
||||
shadow(projects.core) {
|
||||
exclude(group = "com.google.guava", module = "guava")
|
||||
exclude(group = "com.google.code.gson", module = "gson")
|
||||
exclude(group = "org.slf4j")
|
||||
exclude(group = "com.nukkitx.fastutil")
|
||||
exclude(group = "io.netty.incubator")
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
mixin.defaultRefmapName.set("geyser-fabric-refmap.json")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://repo.opencollab.dev/maven-releases/")
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
|
||||
}
|
||||
|
||||
tasks {
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this task, sources will not be generated.
|
||||
sourcesJar {
|
||||
archiveClassifier.set("sources")
|
||||
from(sourceSets.main.get().allSource)
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
// Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
|
||||
configurations = listOf(project.configurations.shadow.get())
|
||||
// The remapped shadowJar is the final desired Geyser-Fabric.jar
|
||||
archiveVersion.set(project.version.toString())
|
||||
archiveClassifier.set("shaded")
|
||||
|
||||
relocate("org.objectweb.asm", "org.geysermc.relocate.asm")
|
||||
relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139
|
||||
relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson")
|
||||
relocate("net.kyori", "org.geysermc.relocate.kyori")
|
||||
|
||||
dependencies {
|
||||
// Exclude everything EXCEPT some DNS stuff required for HAProxy
|
||||
exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-classes-kqueue:.*"))
|
||||
exclude(dependency("io.netty:netty-transport-native-kqueue:.*"))
|
||||
exclude(dependency("io.netty:netty-handler:.*"))
|
||||
exclude(dependency("io.netty:netty-common:.*"))
|
||||
exclude(dependency("io.netty:netty-buffer:.*"))
|
||||
exclude(dependency("io.netty:netty-resolver:.*"))
|
||||
exclude(dependency("io.netty:netty-transport:.*"))
|
||||
exclude(dependency("io.netty:netty-codec:.*"))
|
||||
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
||||
exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
remapJar {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.get().archiveFile)
|
||||
archiveBaseName.set("Geyser-Fabric")
|
||||
archiveVersion.set("")
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
|
||||
register("remapModrinthJar", RemapJarTask::class) {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.get().archiveFile)
|
||||
archiveBaseName.set("geyser-fabric")
|
||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
}
|
||||
|
||||
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", "1.20.1")
|
||||
|
||||
loaders.add("fabric")
|
||||
failSilently.set(true)
|
||||
|
||||
dependencies {
|
||||
required.project("fabric-api")
|
||||
}
|
||||
}
|
|
@ -1,297 +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.platform.fabric;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.level.WorldManager;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
|
||||
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||
private static GeyserFabricMod instance;
|
||||
|
||||
private boolean reloading;
|
||||
|
||||
private GeyserImpl geyser;
|
||||
private ModContainer mod;
|
||||
private Path dataFolder;
|
||||
private MinecraftServer server;
|
||||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserFabricConfiguration geyserConfig;
|
||||
private GeyserFabricLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private WorldManager geyserWorldManager;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
instance = this;
|
||||
mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
|
||||
|
||||
this.onEnable();
|
||||
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
|
||||
// Set as an event so we can get the proper IP and port if needed
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(this::startGeyser);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric");
|
||||
if (!dataFolder.toFile().exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dataFolder.toFile().mkdir();
|
||||
}
|
||||
|
||||
// Init dataFolder first as local language overrides call getConfigFolder()
|
||||
GeyserLocale.init(this);
|
||||
|
||||
try {
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
|
||||
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.FABRIC, this);
|
||||
|
||||
if (server == null) {
|
||||
// Server has yet to start
|
||||
// Register onDisable so players are properly kicked
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable());
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler));
|
||||
} else {
|
||||
// Server has started and this is a reload
|
||||
startGeyser(this.server);
|
||||
reloading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize core Geyser.
|
||||
* A function, as it needs to be called in different places depending on if Geyser is being reloaded or not.
|
||||
*
|
||||
* @param server The minecraft server.
|
||||
*/
|
||||
public void startGeyser(MinecraftServer server) {
|
||||
this.server = server;
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
|
||||
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||
this.geyserCommandManager.init();
|
||||
|
||||
this.geyserWorldManager = new GeyserFabricWorldManager(server);
|
||||
|
||||
// Start command building
|
||||
// Set just "geyser" as the help command
|
||||
GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||
(GeyserCommand) geyser.commandManager().getCommands().get("help"));
|
||||
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
|
||||
|
||||
// Register all subcommands as valid
|
||||
for (Map.Entry<String, Command> command : geyser.commandManager().getCommands().entrySet()) {
|
||||
GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
|
||||
builder.then(Commands.literal(command.getKey())
|
||||
.executes(executor)
|
||||
// Could also test for Bedrock but depending on when this is called it may backfire
|
||||
.requires(executor::testPermission)
|
||||
// Allows parsing of arguments; e.g. for /geyser dump logs or the connectiontest command
|
||||
.then(Commands.argument("args", StringArgumentType.greedyString())
|
||||
.executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args")))
|
||||
.requires(executor::testPermission)));
|
||||
}
|
||||
server.getCommands().getDispatcher().register(builder);
|
||||
|
||||
// Register extension commands
|
||||
for (Map.Entry<Extension, Map<String, Command>> extensionMapEntry : geyser.commandManager().extensionCommands().entrySet()) {
|
||||
Map<String, Command> extensionCommands = extensionMapEntry.getValue();
|
||||
if (extensionCommands.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register help command for just "/<extensionId>"
|
||||
GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||
(GeyserCommand) extensionCommands.get("help"));
|
||||
LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
|
||||
|
||||
for (Map.Entry<String, Command> command : extensionCommands.entrySet()) {
|
||||
GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
|
||||
extCmdBuilder.then(Commands.literal(command.getKey())
|
||||
.executes(executor)
|
||||
.requires(executor::testPermission)
|
||||
.then(Commands.argument("args", StringArgumentType.greedyString())
|
||||
.executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args")))
|
||||
.requires(executor::testPermission)));
|
||||
}
|
||||
server.getCommands().getDispatcher().register(extCmdBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (geyser != null) {
|
||||
geyser.shutdown();
|
||||
geyser = null;
|
||||
}
|
||||
if (!reloading) {
|
||||
this.server = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserLogger getGeyserLogger() {
|
||||
return geyserLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserCommandManager getGeyserCommandManager() {
|
||||
return geyserCommandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return geyserPingPassthrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldManager getWorldManager() {
|
||||
return geyserWorldManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getConfigFolder() {
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BootstrapDumpInfo getDumpInfo() {
|
||||
return new GeyserFabricDumpInfo(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMinecraftServerVersion() {
|
||||
return this.server.getServerVersion();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getServerBindAddress() {
|
||||
String ip = this.server.getLocalIp();
|
||||
return ip != null ? ip : ""; // See issue #3812
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
||||
if (floodgate.isPresent()) {
|
||||
geyserConfig.loadFloodgate(this, floodgate.orElse(null));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public InputStream getResourceOrNull(String resource) {
|
||||
// We need to handle this differently, because Fabric shares the classloader across multiple mods
|
||||
Path path = this.mod.findPath(resource).orElse(null);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return path.getFileSystem()
|
||||
.provider()
|
||||
.newInputStream(path);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setReloading(boolean reloading) {
|
||||
this.reloading = reloading;
|
||||
}
|
||||
|
||||
public static GeyserFabricMod getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
|
@ -1,79 +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.platform.fabric.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
||||
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
|
||||
private final GeyserCommand command;
|
||||
|
||||
public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
|
||||
super(connector, Collections.singletonMap(command.name(), command));
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public boolean testPermission(CommandSourceStack source) {
|
||||
return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(CommandContext context) {
|
||||
return runWithArgs(context, "");
|
||||
}
|
||||
|
||||
public int runWithArgs(CommandContext context, String args) {
|
||||
CommandSourceStack source = (CommandSourceStack) context.getSource();
|
||||
FabricCommandSender sender = new FabricCommandSender(source);
|
||||
GeyserSession session = getGeyserSession(sender);
|
||||
if (!testPermission(source)) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
|
||||
return 0;
|
||||
}
|
||||
if (this.command.name().equals("reload")) {
|
||||
GeyserFabricMod.getInstance().setReloading(true);
|
||||
}
|
||||
|
||||
if (command.isBedrockOnly() && session == null) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
command.execute(session, sender, args.split(" "));
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,285 +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.platform.fabric.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.WritableBookItem;
|
||||
import net.minecraft.world.item.WrittenBookItem;
|
||||
import net.minecraft.world.level.block.entity.BannerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
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.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||
private final MinecraftServer server;
|
||||
|
||||
public GeyserFabricWorldManager(MinecraftServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
LevelChunk chunk = player.level().getChunk(x, z);
|
||||
final int chunkBlockX = x << 4;
|
||||
final int chunkBlockZ = z << 4;
|
||||
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;
|
||||
}
|
||||
|
||||
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 = WrittenBookItem.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 && WritableBookItem.makeSureTagIsValid(book.getTag())) {
|
||||
ListTag listTag = book.getTag().getList("pages", 8);
|
||||
|
||||
for (int i = 0; i < listTag.size(); i++) {
|
||||
String page = listTag.getString(i);
|
||||
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
|
||||
public boolean hasPermission(GeyserSession session, String permission) {
|
||||
ServerPlayer player = getPlayer(session);
|
||||
return Permissions.check(player, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameMode getDefaultGameMode(GeyserSession session) {
|
||||
return GameMode.byId(server.getDefaultGameType().getId());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CompletableFuture<com.github.steveice10.opennbt.tag.builtin.CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||
CompletableFuture<com.github.steveice10.opennbt.tag.builtin.CompoundTag> future = new CompletableFuture<>();
|
||||
server.execute(() -> {
|
||||
ServerPlayer player = getPlayer(session);
|
||||
if (player == null) {
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
// Don't create a new block entity if invalid
|
||||
BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos);
|
||||
if (blockEntity instanceof BannerBlockEntity banner) {
|
||||
// Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and*
|
||||
// the banner might have a custom name, both of which a Java client knows and caches
|
||||
ItemStack itemStack = banner.getItem();
|
||||
var tag = OpenNbtTagVisitor.convert("", itemStack.getOrCreateTag());
|
||||
|
||||
future.complete(tag);
|
||||
return;
|
||||
}
|
||||
future.complete(null);
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private ServerPlayer getPlayer(GeyserSession session) {
|
||||
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
||||
}
|
||||
|
||||
// Future considerations: option to clone; would affect arrays
|
||||
private static class OpenNbtTagVisitor implements TagVisitor {
|
||||
private String currentKey;
|
||||
private final com.github.steveice10.opennbt.tag.builtin.CompoundTag root;
|
||||
private com.github.steveice10.opennbt.tag.builtin.Tag currentTag;
|
||||
|
||||
OpenNbtTagVisitor(String key) {
|
||||
root = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitString(StringTag stringTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.StringTag(currentKey, stringTag.getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitByte(ByteTag byteTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteTag(currentKey, byteTag.getAsByte());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitShort(ShortTag shortTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.ShortTag(currentKey, shortTag.getAsShort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInt(IntTag intTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.IntTag(currentKey, intTag.getAsInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLong(LongTag longTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.LongTag(currentKey, longTag.getAsLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFloat(FloatTag floatTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.FloatTag(currentKey, floatTag.getAsFloat());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDouble(DoubleTag doubleTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.DoubleTag(currentKey, doubleTag.getAsDouble());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitByteArray(ByteArrayTag byteArrayTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteArrayTag(currentKey, byteArrayTag.getAsByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntArray(IntArrayTag intArrayTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.IntArrayTag(currentKey, intArrayTag.getAsIntArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLongArray(LongArrayTag longArrayTag) {
|
||||
currentTag = new com.github.steveice10.opennbt.tag.builtin.LongArrayTag(currentKey, longArrayTag.getAsLongArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitList(ListTag listTag) {
|
||||
var newList = new com.github.steveice10.opennbt.tag.builtin.ListTag(currentKey);
|
||||
for (Tag tag : listTag) {
|
||||
currentKey = "";
|
||||
tag.accept(this);
|
||||
newList.add(currentTag);
|
||||
}
|
||||
currentTag = newList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCompound(CompoundTag compoundTag) {
|
||||
currentTag = convert(currentKey, compoundTag);
|
||||
}
|
||||
|
||||
private static com.github.steveice10.opennbt.tag.builtin.CompoundTag convert(String name, CompoundTag compoundTag) {
|
||||
OpenNbtTagVisitor visitor = new OpenNbtTagVisitor(name);
|
||||
for (String key : compoundTag.getAllKeys()) {
|
||||
visitor.currentKey = key;
|
||||
Tag tag = compoundTag.get(key);
|
||||
tag.accept(visitor);
|
||||
visitor.root.put(visitor.currentTag);
|
||||
}
|
||||
return visitor.root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd(EndTag endTag) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "org.geysermc.geyser.platform.fabric.mixin",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"refmap": "geyser-fabric-refmap.json",
|
||||
"client": [
|
||||
"client.IntegratedServerMixin"
|
||||
],
|
||||
"server": [
|
||||
"server.MinecraftDedicatedServerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
23
bootstrap/mod/build.gradle.kts
Normal file
23
bootstrap/mod/build.gradle.kts
Normal file
|
@ -0,0 +1,23 @@
|
|||
architectury {
|
||||
common("neoforge", "fabric")
|
||||
}
|
||||
|
||||
loom {
|
||||
mixin.defaultRefmapName.set("geyser-refmap.json")
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
// We don't need these
|
||||
tasks.named("remapModrinthJar").configure {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core)
|
||||
compileOnly(libs.mixin)
|
||||
compileOnly(libs.mixinextras)
|
||||
|
||||
// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
|
||||
compileOnly(libs.fabric.loader)
|
||||
}
|
62
bootstrap/mod/fabric/build.gradle.kts
Normal file
62
bootstrap/mod/fabric/build.gradle.kts
Normal file
|
@ -0,0 +1,62 @@
|
|||
architectury {
|
||||
platformSetupLoomIde()
|
||||
fabric()
|
||||
}
|
||||
|
||||
val includeTransitive: Configuration = configurations.getByName("includeTransitive")
|
||||
|
||||
dependencies {
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.fabric.api)
|
||||
|
||||
api(project(":mod", configuration = "namedElements"))
|
||||
shadow(project(path = ":mod", configuration = "transformProductionFabric")) {
|
||||
isTransitive = false
|
||||
}
|
||||
shadow(projects.core) { isTransitive = false }
|
||||
includeTransitive(projects.core)
|
||||
|
||||
// These are NOT transitively included, and instead shadowed + relocated.
|
||||
// Avoids fabric complaining about non-SemVer versioning
|
||||
shadow(libs.protocol.connection) { isTransitive = false }
|
||||
shadow(libs.protocol.common) { isTransitive = false }
|
||||
shadow(libs.protocol.codec) { isTransitive = false }
|
||||
shadow(libs.raknet) { isTransitive = false }
|
||||
shadow(libs.mcprotocollib) { isTransitive = false }
|
||||
|
||||
// Since we also relocate cloudburst protocol: shade erosion common
|
||||
shadow(libs.erosion.common) { isTransitive = false }
|
||||
|
||||
// Let's shade in our own api/common module
|
||||
shadow(projects.api) { isTransitive = false }
|
||||
shadow(projects.common) { isTransitive = false }
|
||||
|
||||
modImplementation(libs.cloud.fabric)
|
||||
include(libs.cloud.fabric)
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.fabric.GeyserFabricMain"
|
||||
}
|
||||
|
||||
relocate("org.cloudburstmc.netty")
|
||||
relocate("org.cloudburstmc.protocol")
|
||||
relocate("com.github.steveice10.mc.auth")
|
||||
|
||||
tasks {
|
||||
remapJar {
|
||||
archiveBaseName.set("Geyser-Fabric")
|
||||
}
|
||||
|
||||
remapModrinthJar {
|
||||
archiveBaseName.set("geyser-fabric")
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
loaders.add("fabric")
|
||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||
dependencies {
|
||||
required.project("fabric-api")
|
||||
}
|
||||
}
|
1
bootstrap/mod/fabric/gradle.properties
Normal file
1
bootstrap/mod/fabric/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
loom.platform=fabric
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.fabric;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
||||
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.fabric.FabricServerCommandManager;
|
||||
|
||||
public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {
|
||||
|
||||
public GeyserFabricBootstrap() {
|
||||
super(new GeyserFabricPlatform());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
if (isServer()) {
|
||||
// Set as an event, so we can get the proper IP and port if needed
|
||||
ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
|
||||
this.setServer(server);
|
||||
onGeyserEnable();
|
||||
});
|
||||
} else {
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(($)-> {
|
||||
onGeyserShutdown();
|
||||
});
|
||||
}
|
||||
|
||||
// These are only registered once
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
|
||||
if (isServer()) {
|
||||
onGeyserShutdown();
|
||||
} else {
|
||||
onGeyserDisable();
|
||||
}
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
|
||||
|
||||
this.onGeyserInitialize();
|
||||
|
||||
var sourceConverter = CommandSourceConverter.layered(
|
||||
CommandSourceStack.class,
|
||||
id -> getServer().getPlayerList().getPlayer(id),
|
||||
Player::createCommandSourceStack,
|
||||
() -> getServer().createCommandSourceStack(), // NPE if method reference is used, since server is not available yet
|
||||
ModCommandSource::new
|
||||
);
|
||||
CommandManager<GeyserCommandSource> cloud = new FabricServerCommandManager<>(
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
sourceConverter
|
||||
);
|
||||
this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud, false)); // applying root permission would be a breaking change because we can't register permission defaults
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServer() {
|
||||
return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER);
|
||||
}
|
||||
}
|
|
@ -43,21 +43,27 @@ import java.util.stream.Collectors;
|
|||
@Getter
|
||||
public class GeyserFabricDumpInfo extends BootstrapDumpInfo {
|
||||
|
||||
private String platformVersion = null;
|
||||
private final String platformName;
|
||||
private String platformVersion;
|
||||
private final String minecraftVersion;
|
||||
private final EnvType environmentType;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final boolean onlineMode;
|
||||
private final List<ModInfo> mods;
|
||||
|
||||
public GeyserFabricDumpInfo(MinecraftServer server) {
|
||||
this.platformName = server.getServerModName();
|
||||
FabricLoader.getInstance().getModContainer("fabricloader").ifPresent(mod ->
|
||||
this.platformVersion = mod.getMetadata().getVersion().getFriendlyString());
|
||||
|
||||
this.minecraftVersion = server.getServerVersion();
|
||||
this.environmentType = FabricLoader.getInstance().getEnvironmentType();
|
||||
this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp();
|
||||
this.serverPort = server.getPort();
|
||||
this.onlineMode = server.usesAuthentication();
|
||||
this.mods = new ArrayList<>();
|
||||
|
||||
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.fabric;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GeyserFabricPlatform implements GeyserModPlatform {
|
||||
|
||||
private final ModContainer mod;
|
||||
|
||||
public GeyserFabricPlatform() {
|
||||
this.mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.FABRIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String configPath() {
|
||||
return "Geyser-Fabric";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Path dataFolder(@NonNull String modId) {
|
||||
return FabricLoader.getInstance().getConfigDir().resolve(modId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
|
||||
return new GeyserFabricDumpInfo(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
|
||||
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
||||
if (floodgate.isPresent()) {
|
||||
Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate");
|
||||
bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable InputStream resolveResource(@NonNull String resource) {
|
||||
// We need to handle this differently, because Fabric shares the classloader across multiple mods
|
||||
Path path = this.mod.findPath(resource).orElse(null);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return path.getFileSystem()
|
||||
.provider()
|
||||
.newInputStream(path);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,23 +9,22 @@
|
|||
],
|
||||
"contact": {
|
||||
"website": "${url}",
|
||||
"repo": "https://github.com/GeyserMC/Geyser-Fabric"
|
||||
"repo": "https://github.com/GeyserMC/Geyser"
|
||||
},
|
||||
"license": "MIT",
|
||||
"icon": "assets/geyser-fabric/icon.png",
|
||||
"icon": "assets/geyser/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"org.geysermc.geyser.platform.fabric.GeyserFabricMod"
|
||||
"org.geysermc.geyser.platform.fabric.GeyserFabricBootstrap"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"geyser-fabric.mixins.json"
|
||||
"geyser.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.21",
|
||||
"fabricloader": ">=0.15.11",
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.20",
|
||||
"fabric-permissions-api-v0": "*"
|
||||
"minecraft": ">=1.21"
|
||||
}
|
||||
}
|
59
bootstrap/mod/neoforge/build.gradle.kts
Normal file
59
bootstrap/mod/neoforge/build.gradle.kts
Normal file
|
@ -0,0 +1,59 @@
|
|||
// This is provided by "org.cloudburstmc.math.mutable" too, so yeet.
|
||||
// NeoForge's class loader is *really* annoying.
|
||||
provided("org.cloudburstmc.math", "api")
|
||||
provided("com.google.errorprone", "error_prone_annotations")
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
neoForge()
|
||||
}
|
||||
|
||||
val includeTransitive: Configuration = configurations.getByName("includeTransitive")
|
||||
|
||||
dependencies {
|
||||
// See https://github.com/google/guava/issues/6618
|
||||
modules {
|
||||
module("com.google.guava:listenablefuture") {
|
||||
replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
|
||||
}
|
||||
}
|
||||
|
||||
neoForge(libs.neoforge.minecraft)
|
||||
|
||||
api(project(":mod", configuration = "namedElements"))
|
||||
shadow(project(path = ":mod", configuration = "transformProductionNeoForge")) {
|
||||
isTransitive = false
|
||||
}
|
||||
shadow(projects.core) { isTransitive = false }
|
||||
|
||||
// Let's shade in our own api
|
||||
shadow(projects.api) { 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
|
||||
includeTransitive(projects.core)
|
||||
|
||||
modImplementation(libs.cloud.neoforge)
|
||||
include(libs.cloud.neoforge)
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
manifest.attributes["Main-Class"] = "org.geysermc.geyser.platform.neoforge.GeyserNeoForgeMain"
|
||||
}
|
||||
|
||||
tasks {
|
||||
remapJar {
|
||||
archiveBaseName.set("Geyser-NeoForge")
|
||||
}
|
||||
|
||||
remapModrinthJar {
|
||||
archiveBaseName.set("geyser-neoforge")
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
loaders.add("neoforge")
|
||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||
}
|
1
bootstrap/mod/neoforge/gradle.properties
Normal file
1
bootstrap/mod/neoforge/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
loom.platform=neoforge
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.neoforge;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.GameShuttingDownEvent;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
|
||||
import org.geysermc.geyser.command.CommandSourceConverter;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
||||
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.neoforge.NeoForgeServerCommandManager;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Mod(ModConstants.MOD_ID)
|
||||
public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
||||
|
||||
public GeyserNeoForgeBootstrap(ModContainer container) {
|
||||
super(new GeyserNeoForgePlatform(container));
|
||||
|
||||
if (isServer()) {
|
||||
// Set as an event so we can get the proper IP and port if needed
|
||||
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
|
||||
} else {
|
||||
NeoForge.EVENT_BUS.addListener(this::onClientStopping);
|
||||
}
|
||||
|
||||
NeoForge.EVENT_BUS.addListener(this::onServerStopping);
|
||||
NeoForge.EVENT_BUS.addListener(this::onPlayerJoin);
|
||||
|
||||
NeoForge.EVENT_BUS.addListener(EventPriority.HIGHEST, this::onPermissionGather);
|
||||
|
||||
this.onGeyserInitialize();
|
||||
|
||||
var sourceConverter = CommandSourceConverter.layered(
|
||||
CommandSourceStack.class,
|
||||
id -> getServer().getPlayerList().getPlayer(id),
|
||||
Player::createCommandSourceStack,
|
||||
() -> getServer().createCommandSourceStack(),
|
||||
ModCommandSource::new
|
||||
);
|
||||
CommandManager<GeyserCommandSource> cloud = new NeoForgeServerCommandManager<>(
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
sourceConverter
|
||||
);
|
||||
GeyserNeoForgeCommandRegistry registry = new GeyserNeoForgeCommandRegistry(getGeyser(), cloud);
|
||||
this.setCommandRegistry(registry);
|
||||
NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, registry::onPermissionGatherForUndefined);
|
||||
}
|
||||
|
||||
private void onServerStarted(ServerStartedEvent event) {
|
||||
this.setServer(event.getServer());
|
||||
this.onGeyserEnable();
|
||||
}
|
||||
|
||||
private void onServerStopping(ServerStoppingEvent event) {
|
||||
if (isServer()) {
|
||||
this.onGeyserShutdown();
|
||||
} else {
|
||||
this.onGeyserDisable();
|
||||
}
|
||||
}
|
||||
|
||||
private void onClientStopping(GameShuttingDownEvent ignored) {
|
||||
this.onGeyserShutdown();
|
||||
}
|
||||
|
||||
private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
GeyserModUpdateListener.onPlayReady(event.getEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServer() {
|
||||
return FMLLoader.getDist().isDedicatedServer();
|
||||
}
|
||||
|
||||
private void onPermissionGather(PermissionGatherEvent.Nodes event) {
|
||||
getGeyser().eventBus().fire(
|
||||
(GeyserRegisterPermissionsEvent) (permission, defaultValue) -> {
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
Objects.requireNonNull(defaultValue, "permission default for " + permission);
|
||||
|
||||
if (permission.isBlank()) {
|
||||
return;
|
||||
}
|
||||
PermissionUtils.register(permission, defaultValue, event);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.platform.neoforge;
|
||||
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
|
||||
import org.geysermc.geyser.api.util.TriState;
|
||||
import org.geysermc.geyser.command.CommandRegistry;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.neoforge.PermissionNotRegisteredException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class GeyserNeoForgeCommandRegistry extends CommandRegistry {
|
||||
|
||||
/**
|
||||
* Permissions with an undefined permission default. Use Set to not register the same fallback more than once.
|
||||
* NeoForge requires that all permissions are registered, and cloud-neoforge follows that.
|
||||
* This is unlike most platforms, on which we wouldn't register a permission if no default was provided.
|
||||
*/
|
||||
private final Set<String> undefinedPermissions = new HashSet<>();
|
||||
|
||||
public GeyserNeoForgeCommandRegistry(GeyserImpl geyser, CommandManager<GeyserCommandSource> cloud) {
|
||||
super(geyser, cloud);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void register(GeyserCommand command, Map<String, GeyserCommand> commands) {
|
||||
super.register(command, commands);
|
||||
|
||||
// FIRST STAGE: Collect all permissions that may have undefined defaults.
|
||||
if (!command.permission().isBlank() && command.permissionDefault() == null) {
|
||||
// Permission requirement exists but no default value specified.
|
||||
undefinedPermissions.add(command.permission());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRegisterPermissions(GeyserRegisterPermissionsEvent event) {
|
||||
super.onRegisterPermissions(event);
|
||||
|
||||
// SECOND STAGE
|
||||
// Now that we are aware of all commands, we can eliminate some incorrect assumptions.
|
||||
// Example: two commands may have the same permission, but only of them defines a permission default.
|
||||
undefinedPermissions.removeAll(permissionDefaults.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers permissions with possibly undefined defaults.
|
||||
* Should be subscribed late to allow extensions and mods to register a desired permission default first.
|
||||
*/
|
||||
void onPermissionGatherForUndefined(PermissionGatherEvent.Nodes event) {
|
||||
// THIRD STAGE
|
||||
for (String permission : undefinedPermissions) {
|
||||
if (PermissionUtils.register(permission, TriState.NOT_SET, event)) {
|
||||
// The permission was not already registered
|
||||
geyser.getLogger().debug("Registered permission " + permission + " with fallback default value of NOT_SET");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(GeyserCommandSource source, String permission) {
|
||||
// NeoForgeServerCommandManager will throw this exception if the permission is not registered to the server.
|
||||
// We can't realistically ensure that every permission is registered (calls by API users), so we catch this.
|
||||
// This works for our calls, but not for cloud's internal usage. For that case, see above.
|
||||
try {
|
||||
return super.hasPermission(source, permission);
|
||||
} catch (PermissionNotRegisteredException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.neoforge;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.fml.ModList;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.neoforgespi.language.IModInfo;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class GeyserNeoForgeDumpInfo extends BootstrapDumpInfo {
|
||||
|
||||
private final String platformName;
|
||||
private final String platformVersion;
|
||||
private final String minecraftVersion;
|
||||
private final Dist dist;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final boolean onlineMode;
|
||||
private final List<ModInfo> mods;
|
||||
|
||||
public GeyserNeoForgeDumpInfo(MinecraftServer server) {
|
||||
this.platformName = FMLLoader.launcherHandlerName();
|
||||
this.platformVersion = FMLLoader.versionInfo().neoForgeVersion();
|
||||
this.minecraftVersion = FMLLoader.versionInfo().mcVersion();
|
||||
this.dist = FMLLoader.getDist();
|
||||
this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp();
|
||||
this.serverPort = server.getPort();
|
||||
this.onlineMode = server.usesAuthentication();
|
||||
this.mods = new ArrayList<>();
|
||||
|
||||
for (IModInfo mod : ModList.get().getMods()) {
|
||||
this.mods.add(new ModInfo(
|
||||
ModList.get().isLoaded(mod.getModId()),
|
||||
mod.getModId(),
|
||||
mod.getVersion().toString(),
|
||||
mod.getModURL().map(URL::toString).orElse("")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class ModInfo {
|
||||
public boolean enabled;
|
||||
public String name;
|
||||
public String version;
|
||||
public String url;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
* Copyright (c) 2019-2023 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
|
||||
|
@ -23,16 +23,23 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.translator.collision;
|
||||
package org.geysermc.geyser.platform.neoforge;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.geysermc.geyser.GeyserMain;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@CollisionRemapper(regex = "^spawner$")
|
||||
public class SpawnerCollision extends SolidCollision {
|
||||
public SpawnerCollision(String params) {
|
||||
super(params);
|
||||
// Increase pushAwayTolerance to work around https://bugs.mojang.com/browse/MCPE-41996
|
||||
pushAwayTolerance = 0.0002;
|
||||
public class GeyserNeoForgeMain extends GeyserMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new GeyserNeoForgeMain().displayMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginType() {
|
||||
return "NeoForge";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginFolder() {
|
||||
return "mods";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2023 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.neoforge;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.ModList;
|
||||
import net.neoforged.fml.loading.FMLPaths;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class GeyserNeoForgePlatform implements GeyserModPlatform {
|
||||
|
||||
private final ModContainer container;
|
||||
|
||||
public GeyserNeoForgePlatform(ModContainer container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PlatformType platformType() {
|
||||
return PlatformType.NEOFORGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String configPath() {
|
||||
return "Geyser-NeoForge";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Path dataFolder(@NonNull String modId) {
|
||||
return FMLPaths.CONFIGDIR.get().resolve(modId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
|
||||
return new GeyserNeoForgeDumpInfo(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
|
||||
if (ModList.get().isLoaded("floodgate")) {
|
||||
Path floodgateDataFolder = FMLPaths.CONFIGDIR.get().resolve("floodgate");
|
||||
bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable InputStream resolveResource(@NonNull String resource) {
|
||||
try {
|
||||
Path path = container.getModInfo().getOwningFile().getFile().findResource(resource);
|
||||
return Files.newInputStream(path);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue